[
  {
    "path": ".gitattributes",
    "content": "# Ignore all test and documentation for archive\n/.gitattributes     export-ignore\n/.gitignore         export-ignore\n/.travis.yml        export-ignore\n/phpunit.xml.dist   export-ignore\n/tests              export-ignore"
  },
  {
    "path": ".gitignore",
    "content": "# phpstorm project files\n.idea\n\n# netbeans project files\nnbproject\n\n# zend studio for eclipse project files\n.buildpath\n.project\n.settings\n\n# windows thumbnail cache\nThumbs.db\n\n# composer vendor dir\n/vendor\n\n/composer.lock\n\n# composer itself is not needed\ncomposer.phar\n\n# Mac DS_Store Files\n.DS_Store\n\n# phpunit itself is not needed\nphpunit.phar\n# local phpunit config\n/phpunit.xml\n\n# local tests configuration\n/tests/data/config.local.php\n\n# runtime cache\n/tests/runtime\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: php\n\nphp:\n  - 5.6\n  - 7.0\n  - 7.1\n  - 7.2\n\n# faster builds on new travis setup not using sudo\nsudo: false\n\ninstall:\n#  - composer global require \"fxp/composer-asset-plugin:~1.4.4\"\n  - export PATH=\"$HOME/.composer/vendor/bin:$PATH\"\n  - composer install --prefer-dist --no-interaction\n\n#script:\n#  - phpunit\n"
  },
  {
    "path": "Jwt.php",
    "content": "<?php\n\nnamespace sizeg\\jwt;\n\nuse Lcobucci\\JWT\\Builder;\nuse Lcobucci\\JWT\\Claim\\Factory as ClaimFactory;\nuse Lcobucci\\JWT\\Parser;\nuse Lcobucci\\JWT\\Parsing\\Decoder;\nuse Lcobucci\\JWT\\Parsing\\Encoder;\nuse Lcobucci\\JWT\\Signer;\nuse Lcobucci\\JWT\\Signer\\Key;\nuse Lcobucci\\JWT\\Token;\nuse Lcobucci\\JWT\\ValidationData;\nuse Yii;\nuse yii\\base\\Component;\nuse yii\\base\\InvalidArgumentException;\n\n/**\n * JSON Web Token implementation, based on this library:\n * https://github.com/lcobucci/jwt\n *\n * @author Dmitriy Demin <sizemail@gmail.com>\n * @since 1.0.0-a\n */\nclass Jwt extends Component\n{\n\n    /**\n     * @var array Supported algorithms\n     */\n    public $supportedAlgs = [\n        'HS256' => \\Lcobucci\\JWT\\Signer\\Hmac\\Sha256::class,\n        'HS384' => \\Lcobucci\\JWT\\Signer\\Hmac\\Sha384::class,\n        'HS512' => \\Lcobucci\\JWT\\Signer\\Hmac\\Sha512::class,\n        'ES256' => \\Lcobucci\\JWT\\Signer\\Ecdsa\\Sha256::class,\n        'ES384' => \\Lcobucci\\JWT\\Signer\\Ecdsa\\Sha384::class,\n        'ES512' => \\Lcobucci\\JWT\\Signer\\Ecdsa\\Sha512::class,\n        'RS256' => \\Lcobucci\\JWT\\Signer\\Rsa\\Sha256::class,\n        'RS384' => \\Lcobucci\\JWT\\Signer\\Rsa\\Sha384::class,\n        'RS512' => \\Lcobucci\\JWT\\Signer\\Rsa\\Sha512::class,\n    ];\n\n    /**\n     * @var Key|string $key The key\n     */\n    public $key;\n\n    /**\n     * @var string|array|callable \\sizeg\\jwtJwtValidationData\n     * @see [[Yii::createObject()]]\n     */\n    public $jwtValidationData = JwtValidationData::class;\n\n    /**\n     * @see [[Lcobucci\\JWT\\Builder::__construct()]]\n     * @param Encoder|null $encoder\n     * @param ClaimFactory|null $claimFactory\n     * @return Builder\n     */\n    public function getBuilder(Encoder $encoder = null, ClaimFactory $claimFactory = null)\n    {\n        return new Builder($encoder, $claimFactory);\n    }\n\n    /**\n     * @see [[Lcobucci\\JWT\\Parser::__construct()]]\n     * @param Decoder|null $decoder\n     * @param ClaimFactory|null $claimFactory\n     * @return Parser\n     */\n    public function getParser(Decoder $decoder = null, ClaimFactory $claimFactory = null)\n    {\n        return new Parser($decoder, $claimFactory);\n    }\n\n    /**\n     * @see [[Lcobucci\\JWT\\ValidationData::__construct()]]\n     * @return ValidationData\n     */\n    public function getValidationData()\n    {\n        return Yii::createObject($this->jwtValidationData)->getValidationData();\n    }\n\n    /**\n     * @param string $alg\n     * @return Signer\n     */\n    public function getSigner($alg)\n    {\n        $class = $this->supportedAlgs[$alg];\n\n        return new $class();\n    }\n\n    /**\n     * @param strng $content\n     * @param string|null $passphrase\n     * @return Key\n     */\n    public function getKey($content = null, $passphrase = null)\n    {\n        $content = $content ?: $this->key;\n\n        if ($content instanceof Key) {\n            return $content;\n        }\n\n        return new Key($content, $passphrase);\n    }\n\n    /**\n     * Parses the JWT and returns a token class\n     * @param string $token JWT\n     * @param bool $validate\n     * @param bool $verify\n     * @return Token|null\n     * @throws \\Throwable\n     */\n    public function loadToken($token, $validate = true, $verify = true)\n    {\n        try {\n            $token = $this->getParser()->parse((string) $token);\n        } catch (\\RuntimeException $e) {\n            Yii::warning('Invalid JWT provided: ' . $e->getMessage(), 'jwt');\n            return null;\n        } catch (\\InvalidArgumentException $e) {\n            Yii::warning('Invalid JWT provided: ' . $e->getMessage(), 'jwt');\n            return null;\n        }\n\n        if ($validate && !$this->validateToken($token)) {\n            return null;\n        }\n\n        if ($verify && !$this->verifyToken($token)) {\n            return null;\n        }\n\n        return $token;\n    }\n\n    /**\n     * Validate token\n     * @param Token $token token object\n     * @param int|null $currentTime\n     * @return bool\n     */\n    public function validateToken(Token $token, $currentTime = null)\n    {\n        $validationData = $this->getValidationData();\n        if ($currentTime !== null) {\n            $validationData->setCurrentTime($currentTime);\n        }\n        return $token->validate($validationData);\n    }\n\n    /**\n     * Validate token\n     * @param Token $token token object\n     * @return bool\n     * @throws \\Throwable\n     */\n    public function verifyToken(Token $token)\n    {\n        $alg = $token->getHeader('alg');\n\n        if (empty($this->supportedAlgs[$alg])) {\n            throw new InvalidArgumentException('Algorithm not supported');\n        }\n\n        /** @var Signer $signer */\n        $signer = Yii::createObject($this->supportedAlgs[$alg]);\n\n        return $token->verify($signer, $this->key);\n    }\n}\n"
  },
  {
    "path": "JwtHttpBearerAuth.php",
    "content": "<?php\n\nnamespace sizeg\\jwt;\n\nuse yii\\di\\Instance;\nuse yii\\filters\\auth\\AuthMethod;\n\n/**\n * JwtHttpBearerAuth is an action filter that supports the authentication method based on JSON Web Token.\n *\n * You may use JwtHttpBearerAuth by attaching it as a behavior to a controller or module, like the following:\n *\n * ```php\n * public function behaviors()\n * {\n *     return [\n *         'bearerAuth' => [\n *             'class' => \\sizeg\\jwt\\JwtHttpBearerAuth::className(),\n *         ],\n *     ];\n * }\n * ```\n *\n * @author Dmitriy Demin <sizemail@gmail.com>\n * @since 1.0.0-a\n */\nclass JwtHttpBearerAuth extends AuthMethod\n{\n\n    /**\n     * @var Jwt|string|array the [[Jwt]] object or the application component ID of the [[Jwt]].\n     */\n    public $jwt = 'jwt';\n\n    /**\n     * @var string A \"realm\" attribute MAY be included to indicate the scope\n     * of protection in the manner described in HTTP/1.1 [RFC2617].  The \"realm\"\n     * attribute MUST NOT appear more than once.\n     */\n    public $realm = 'api';\n\n    /**\n     * @var string Authorization header schema, default 'Bearer'\n     */\n    public $schema = 'Bearer';\n\n    /**\n     * @var callable a PHP callable that will authenticate the user with the JWT payload information\n     *\n     * ```php\n     * function ($token, $authMethod) {\n     *    return \\app\\models\\User::findOne($token->getClaim('id'));\n     * }\n     * ```\n     *\n     * If this property is not set, the username information will be considered as an access token\n     * while the password information will be ignored. The [[\\yii\\web\\User::loginByAccessToken()]]\n     * method will be called to authenticate and login the user.\n     */\n    public $auth;\n\n    /**\n     * @inheritdoc\n     */\n    public function init()\n    {\n        parent::init();\n        $this->jwt = Instance::ensure($this->jwt, Jwt::className());\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function authenticate($user, $request, $response)\n    {\n        $authHeader = $request->getHeaders()->get('Authorization');\n        if ($authHeader !== null && preg_match('/^' . $this->schema . '\\s+(.*?)$/', $authHeader, $matches)) {\n            $token = $this->loadToken($matches[1]);\n            if ($token === null) {\n                return null;\n            }\n\n            if ($this->auth) {\n                $identity = call_user_func($this->auth, $token, get_class($this));\n            } else {\n                $identity = $user->loginByAccessToken($token, get_class($this));\n            }\n\n            return $identity;\n        }\n\n        return null;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function challenge($response)\n    {\n        $response->getHeaders()->set(\n            'WWW-Authenticate',\n            \"{$this->schema} realm=\\\"{$this->realm}\\\", error=\\\"invalid_token\\\", error_description=\\\"The access token invalid or expired\\\"\"\n        );\n    }\n\n    /**\n     * Parses the JWT and returns a token class\n     * @param string $token JWT\n     * @return Token|null\n     */\n    public function loadToken($token)\n    {\n        return $this->jwt->loadToken($token);\n    }\n}\n"
  },
  {
    "path": "JwtValidationData.php",
    "content": "<?php\n\nnamespace sizeg\\jwt;\n\nuse Lcobucci\\JWT\\ValidationData;\nuse yii\\base\\Component;\n\n/**\n * Class JwtValidationData\n *\n * @author SiZE <sizemail@gmail.com>\n */\nclass JwtValidationData extends Component\n{\n\n    /**\n     * @var int|null Current time\n     */\n    public $currentTime = null;\n\n    /**\n     * @var int The leeway (in seconds) to use when validating time claims\n     */\n    public $leeway = 0;\n\n    /**\n     * @var ValidationData\n     */\n    protected $validationData;\n\n    /**\n     * ValidationData constructor.\n     * @param ValidationData $validationData\n     * @param array $config\n     */\n    public function __construct($config = [])\n    {\n        $this->validationData = new ValidationData($this->currentTime, $this->leeway);\n        parent::__construct($config);\n    }\n\n    /**\n     * @return ValidationData\n     */\n    public function getValidationData()\n    {\n        return $this->validationData;\n    }\n}"
  },
  {
    "path": "README.md",
    "content": "# Yii2 JWT\n\n![](https://travis-ci.org/sizeg/yii2-jwt.svg)\n\nThis extension provides the [JWT](https://github.com/lcobucci/jwt) integration for the [Yii framework 2.0](http://www.yiiframework.com) (requires PHP 5.6+).\nIt includes basic HTTP authentication support.\n\n## Table of contents\n\n1. [Installation](#installation)\n1. [Dependencies](#dependencies)\n1. [Basic usage](#basicusage)\n   1. [Creating](#basicusage-creating)\n   1. [Parsing from strings](#basicusage-parsing)\n   1. [Validating](#basicusage-validating)\n1. [Token signature](#tokensign)\n   1. [Hmac](#tokensign-hmac)\n   1. [RSA and ECDSA](#tokensign-rsa-ecdsa)\n1. [Yii2 basic template example](#yii2basic-example)\n\n<a name=\"installation\"></a>\n## Installation\n\nPackage is available on [Packagist](https://packagist.org/packages/sizeg/yii2-jwt),\nyou can install it using [Composer](http://getcomposer.org).\n\n```shell\ncomposer require sizeg/yii2-jwt\n```\n\n<a name=\"dependencies\"></a>\n## Dependencies\n\n- PHP 5.6+\n- OpenSSL Extension\n- [lcobucci/jwt 3.3](https://github.com/lcobucci/jwt/tree/3.3)\n\n<a name=\"basicusage\"></a>\n## Basic usage\n\nAdd `jwt` component to your configuration file,\n\n```php\n'components' => [\n    'jwt' => [\n      'class' => \\sizeg\\jwt\\Jwt::class,\n      'key'   => 'secret',\n    ],\n],\n```\n\nConfigure the `authenticator` behavior as follows.\n\n```php\nnamespace app\\controllers;\n\nclass ExampleController extends \\yii\\rest\\Controller\n{\n\n    /**\n     * @inheritdoc\n     */\n    public function behaviors()\n    {\n        $behaviors = parent::behaviors();\n        $behaviors['authenticator'] = [\n            'class' => \\sizeg\\jwt\\JwtHttpBearerAuth::class,\n        ];\n\n        return $behaviors;\n    }\n}\n```\n\nAlso you can use it with `CompositeAuth` reffer to a [doc](http://www.yiiframework.com/doc-2.0/guide-rest-authentication.html).\n\n<a name=\"basicusage-creating\"></a>\n### Creating\n\nSome methods marked as deprecated and will soon backport things from lcobucci/jwt 4.x to create an upgrade path.\n\nJust use the builder to create a new JWT/JWS tokens:\n\n```php\n$time = time();\n$token = Yii::$app->jwt->getBuilder()\n            ->issuedBy('http://example.com') // Configures the issuer (iss claim)\n            ->permittedFor('http://example.org') // Configures the audience (aud claim)\n            ->identifiedBy('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item\n            ->issuedAt($time) // Configures the time that the token was issue (iat claim)\n            ->canOnlyBeUsedAfter($time + 60) // Configures the time that the token can be used (nbf claim)\n            ->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)\n            ->withClaim('uid', 1) // Configures a new claim, called \"uid\"\n            ->getToken(); // Retrieves the generated token\n\n\n$token->getHeaders(); // Retrieves the token headers\n$token->getClaims(); // Retrieves the token claims\n\necho $token->getHeader('jti'); // will print \"4f1g23a12aa\"\necho $token->getClaim('iss'); // will print \"http://example.com\"\necho $token->getClaim('uid'); // will print \"1\"\necho $token; // The string representation of the object is a JWT string (pretty easy, right?)\n```\n\n<a name=\"basicusage-parsing\"></a>\n### Parsing from strings\n\nUse the parser to create a new token from a JWT string (using the previous token as example):\n\n```php\n$token = Yii::$app->jwt->getParser()->parse((string) $token); // Parses from a string\n$token->getHeaders(); // Retrieves the token header\n$token->getClaims(); // Retrieves the token claims\n\necho $token->getHeader('jti'); // will print \"4f1g23a12aa\"\necho $token->getClaim('iss'); // will print \"http://example.com\"\necho $token->getClaim('uid'); // will print \"1\"\n```\n\n<a name=\"basicusage-validating\"></a>\n### Validating\n\nWe can easily validate if the token is valid (using the previous token as example):\n\n```php\n$data = Yii::$app->jwt->getValidationData(); // It will use the current time to validate (iat, nbf and exp)\n$data->setIssuer('http://example.com');\n$data->setAudience('http://example.org');\n$data->setId('4f1g23a12aa');\n\nvar_dump($token->validate($data)); // false, because we created a token that cannot be used before of `time() + 60`\n\n$data->setCurrentTime(time() + 61); // changing the validation time to future\n\nvar_dump($token->validate($data)); // true, because validation information is equals to data contained on the token\n\n$data->setCurrentTime(time() + 4000); // changing the validation time to future\n\nvar_dump($token->validate($data)); // false, because token is expired since current time is greater than exp\n```\n\nWe can also use the $leeway parameter to deal with clock skew (see notes below).\nIf token's claimed time is invalid but the difference between that and the validation time is less than $leeway,\nthen token is still considered valid\n```php\n'components' => [\n    'jwt' => [\n        'class' => \\sizeg\\jwt\\Jwt:class,\n        'key'   => 'secret',\n        'jwtValidationData' => [\n            'class' => \\sizeg\\jwt\\JwtValidationData::class,\n             // configure leeway \n            'leeway' => 20,\n        ],\n    ],\n],\n```\n\n```php\n$dataWithLeeway = Yii::$app->jwt->getValidationData();\n$dataWithLeeway->setIssuer('http://example.com');\n$dataWithLeeway->setAudience('http://example.org');\n$dataWithLeeway->setId('4f1g23a12aa');\n\nvar_dump($token->validate($dataWithLeeway)); // false, because token can't be used before now() + 60, not within leeway\n\n$dataWithLeeway->setCurrentTime($time + 61); // changing the validation time to future\n\nvar_dump($token->validate($dataWithLeeway)); // true, because current time plus leeway is between \"nbf\" and \"exp\" claims\n\n$dataWithLeeway->setCurrentTime($time + 3610); // changing the validation time to future but within leeway\n\nvar_dump($token->validate($dataWithLeeway)); // true, because current time - 20 seconds leeway is less than exp\n\n$dataWithLeeway->setCurrentTime($time + 4000); // changing the validation time to future outside of leeway\n\nvar_dump($token->validate($dataWithLeeway)); // false, because token is expired since current time is greater than exp\n```\n\n#### Important\n\n* You have to configure `ValidationData` informing all claims you want to validate the token.\n* If `ValidationData` contains claims that are not being used in token or token has claims that are not configured in `ValidationData` they will be ignored by `Token::validate()`.\n* `exp`, `nbf` and `iat` claims are configured by default in `ValidationData::__construct()` with the current UNIX time (`time()`).\n* The optional `$leeway` parameter of `ValidationData` will cause us to use that number of seconds of leeway when validating the time-based claims,\npretending we are further in the future for the \"Issued At\" (`iat`) and \"Not Before\" (`nbf`) claims and pretending we are further in the past\nfor the \"Expiration Time\" (`exp`) claim. This allows for situations where the clock of the issuing server has a different time than the clock\nof the verifying server, as mentioned in section 4.1 of RFC 7519.\n\n<a name=\"tokensign\"></a>\n## Token signature\n\nWe can use signatures to be able to verify if the token was not modified after its generation.\nThis extension implements Hmac, RSA and ECDSA signatures (using 256, 384 and 512).\n\n### Important\n\nDo not allow the string sent to the Parser to dictate which signature algorithm to use,\nor else your application will be vulnerable to a [critical JWT security vulnerability](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries).\n\nThe examples below are safe because the choice in `Signer` is hard-coded and cannot be influenced by malicious users.\n\n<a name=\"tokensign-hmac\"></a>\n### Hmac\n\nHmac signatures are really simple to be used:\n\n```php\n$jwt = Yii::$app->jwt;\n$signer = $jwt->getSigner('HS256');\n$key = $jwt->getKey();\n$time = time();\n\n$token = $jwt->getBuilder()\n            ->issuedBy('http://example.com') // Configures the issuer (iss claim)\n            ->permittedFor('http://example.org') // Configures the audience (aud claim)\n            ->identifiedBy('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item\n            ->issuedAt($time) // Configures the time that the token was issue (iat claim)\n            ->canOnlyBeUsedAfter($time + 60) // Configures the time that the token can be used (nbf claim)\n            ->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)\n            ->withClaim('uid', 1) // Configures a new claim, called \"uid\"\n            ->getToken($signer, $key); // Retrieves the generated token\n\nvar_dump($token->verify($signer, 'testing 1')); // false, because the key is different\nvar_dump($token->verify($signer, 'testing')); // true, because the key is the same\n```\n\n<a name=\"tokensign-rsa-ecdsa\"></a>\n### RSA and ECDSA\n\nRSA and ECDSA signatures are based on public and private keys so you have to generate using the private key and verify using the public key:\n\n```php\n$jwt = Yii::$app->jwt;\n$signer = $jwt->getSigner('RS256'); // you can use 'ES256' if you're using ECDSA keys\n$privateKey = $jwt->getKey('file://{path to your private key}');\n$time = time();\n\n$token = $jwt->getBuilder()\n            ->issuedBy('http://example.com') // Configures the issuer (iss claim)\n            ->permittedFor('http://example.org') // Configures the audience (aud claim)\n            ->identifiedBy('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item\n            ->issuedAt($time) // Configures the time that the token was issue (iat claim)\n            ->canOnlyBeUsedAfter($time + 60) // Configures the time that the token can be used (nbf claim)\n            ->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)\n            ->withClaim('uid', 1) // Configures a new claim, called \"uid\"\n            ->getToken($signer, $privateKey); // Retrieves the generated token\n            \n$publicKey = $jwt->getKey('file://{path to your public key}');\n\nvar_dump($token->verify($signer, $publicKey)); // true when the public key was generated by the private one =)\n```\n\n**It's important to say that if you're using RSA keys you shouldn't invoke ECDSA signers (and vice-versa), otherwise ```sign()``` and ```verify()``` will raise an exception!**\n\n<a name=\"yii2basic-example\"></a>\n## Yii2 basic template example\n\n### Basic scheme\n\n1. Client send credentials. For example, login + password\n2. Backend validate them\n3. If credentials is valid client receive token\n4. Client store token for the future requests\n\n### Step-by-step usage example\n\n1. Create Yii2 application\n\n    In this example we will use [basic template](https://github.com/yiisoft/yii2-app-basic), but you can use [advanced template](https://github.com/yiisoft/yii2-app-advanced) in the same way.\n\n    ```shell\n    composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic yii2-jwt-test\n    ```\n\n2. Install component\n\n    ```shell\n    composer require sizeg/yii2-jwt\n    ```\n\n3. Add to config/web.php into `components` section\n\n    ```php\n    $config = [\n        'components' => [\n            // other default components here..\n            'jwt' => [\n                'class' => \\sizeg\\jwt\\Jwt::class,\n                'key' => 'secret',\n                // You have to configure ValidationData informing all claims you want to validate the token.\n                'jwtValidationData' => \\app\\components\\JwtValidationData::class,\n            ],\n        ],\n    ];\n    ```\n    \n4. Create JwtValidationData class. Where you have to configure ValidationData informing all claims you want to validate the token.\n \n    ```php\n    <?php\n    \n    namespace app\\components;\n    \n    class JwtValidationData extends \\sizeg\\jwt\\JwtValidationData\n    {\n     \n        /**\n         * @inheritdoc\n         */\n        public function init()\n        {\n            $this->validationData->setIssuer('http://example.com');\n            $this->validationData->setAudience('http://example.org');\n            $this->validationData->setId('4f1g23a12aa');\n    \n            parent::init();\n        }\n    }    \n    ```\n\n5. Change method `app\\models\\User::findIdentityByAccessToken()`\n\n    ```php\n        /**\n         * {@inheritdoc}\n         * @param \\Lcobucci\\JWT\\Token $token\n         */\n        public static function findIdentityByAccessToken($token, $type = null)\n        {\n            foreach (self::$users as $user) {\n                if ($user['id'] === (string) $token->getClaim('uid')) {\n                    return new static($user);\n                }\n            }\n    \n            return null;\n        }\n    ```\n\n6. Create controller\n\n    ```php\n    <?php\n    \n    namespace app\\controllers;\n    \n    use sizeg\\jwt\\Jwt;\n    use sizeg\\jwt\\JwtHttpBearerAuth;\n    use Yii;\n    use yii\\rest\\Controller;\n    \n    class RestController extends Controller\n    {\n        /**\n         * @inheritdoc\n         */\n        public function behaviors()\n        {\n            $behaviors = parent::behaviors();\n            $behaviors['authenticator'] = [\n                'class' => JwtHttpBearerAuth::class,\n                'optional' => [\n                    'login',\n                ],\n            ];\n    \n            return $behaviors;\n        }\n    \n        /**\n         * @return \\yii\\web\\Response\n         */\n        public function actionLogin()\n        {\n            /** @var Jwt $jwt */\n            $jwt = Yii::$app->jwt;\n            $signer = $jwt->getSigner('HS256');\n            $key = $jwt->getKey();\n            $time = time();\n    \n            // Previous implementation\n            /*\n            $token = $jwt->getBuilder()\n                ->setIssuer('http://example.com')// Configures the issuer (iss claim)\n                ->setAudience('http://example.org')// Configures the audience (aud claim)\n                ->setId('4f1g23a12aa', true)// Configures the id (jti claim), replicating as a header item\n                ->setIssuedAt(time())// Configures the time that the token was issue (iat claim)\n                ->setExpiration(time() + 3600)// Configures the expiration time of the token (exp claim)\n                ->set('uid', 100)// Configures a new claim, called \"uid\"\n                ->sign($signer, $jwt->key)// creates a signature using [[Jwt::$key]]\n                ->getToken(); // Retrieves the generated token\n            */\n    \n            // Adoption for lcobucci/jwt ^4.0 version\n            $token = $jwt->getBuilder()\n                ->issuedBy('http://example.com')// Configures the issuer (iss claim)\n                ->permittedFor('http://example.org')// Configures the audience (aud claim)\n                ->identifiedBy('4f1g23a12aa', true)// Configures the id (jti claim), replicating as a header item\n                ->issuedAt($time)// Configures the time that the token was issue (iat claim)\n                ->expiresAt($time + 3600)// Configures the expiration time of the token (exp claim)\n                ->withClaim('uid', 100)// Configures a new claim, called \"uid\"\n                ->getToken($signer, $key); // Retrieves the generated token\n    \n            return $this->asJson([\n                'token' => (string)$token,\n            ]);\n        }\n    \n        /**\n         * @return \\yii\\web\\Response\n         */\n        public function actionData()\n        {\n            return $this->asJson([\n                'success' => true,\n            ]);\n        }\n    }\n    ```\n\n7. Send simple login request to get token. Here we does not send any credentials to simplify example. As we specify in `authenticator` behavior action `login` as optional the `authenticator` skip auth check for that action.\n![image](https://user-images.githubusercontent.com/4047591/54614758-c4d2e100-4a7e-11e9-9175-0f1742bf4047.png)\n\n8. First of all we try to send request to rest/data without token and getting error `Unauthorized`\n![image](https://user-images.githubusercontent.com/4047591/54615287-a3262980-4a7f-11e9-81a9-609f5cb443c7.png)\n\n9. Then we retry request but already adding `Authorization` header with our token\n![image](https://user-images.githubusercontent.com/4047591/54615245-8ee22c80-4a7f-11e9-9948-e3f801596c43.png)\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"sizeg/yii2-jwt\",\n    \"description\": \"JWT based on Icobucci\",\n\t\"type\": \"yii2-extension\",\n\t\"keywords\": [\"yii2\", \"yii 2\", \"jwt\"],\n\t\"authors\": [\n        {\n            \"name\": \"Dmitriy Demin\",\n            \"email\": \"sizemail@gmail.com\",\n            \"homepage\": \"https://sizeg.tk\"\n        }\n    ],\n    \"license\": \"BSD-3-Clause\",\n    \"require\": {\n        \"php\": \">=5.6.0\",\n        \"lcobucci/jwt\": \"~3.3.0\",\n        \"yiisoft/yii2\": \"~2.0.0\"\n    },\n\t\"require-dev\": {\n\t\t\"phpunit/phpunit\": \"^4.8\"\n\t},\n    \"autoload\": {\n        \"psr-4\": {\n            \"sizeg\\\\jwt\\\\\": \"\"\n        }\n    },\n\t\"autoload-dev\": {\n        \"psr-4\": {\n            \"sizeg\\\\jwt\\\\tests\\\\\": \"tests/\"\n        }\n    },\n    \"repositories\": [\n        {\n            \"type\": \"composer\",\n            \"url\": \"https://asset-packagist.org\"\n        }\n    ]    \n}\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<phpunit bootstrap=\"./tests/bootstrap.php\"\n         colors=\"true\"\n         convertErrorsToExceptions=\"true\"\n         convertNoticesToExceptions=\"true\"\n         convertWarningsToExceptions=\"true\"\n         stopOnFailure=\"false\">\n    <testsuites>\n        <testsuite name=\"Test Suite\">\n            <directory>./tests</directory>\n        </testsuite>\n    </testsuites>\n    <filter>\n        <whitelist>\n            <directory suffix=\".php\">./</directory>\n        </whitelist>\n    </filter>\n</phpunit>"
  },
  {
    "path": "tests/JwtTest.php",
    "content": "<?php\n\nnamespace sizeg\\jwt\\tests;\n\nclass JwtTest extends TestCase\n{\n\n    /**\n     * Secret key\n     */\n    const SECRET = 'secret';\n    \n    /**\n     * Issuer\n     */\n    const ISSUER = 'http://example.com';\n    \n    /**\n     * Audience\n     */\n    const AUDIENCE = 'http://example.org';\n    \n    /**\n     * Id\n     */\n    const ID = '4f1g23a12aa';\n\n    /**\n     * @var Jwt\n     */\n    public $jwt;\n\n    /**\n     * @ineritdoc\n     */\n    public function setUp()\n    {\n        $this->jwt = \\Yii::createObject(\\sizeg\\jwt\\Jwt::class, [\n            ['key' => self::SECRET]\n        ]);\n    }\n\n    /**\n     * @return Sha256 signer\n     */\n    public function getSignerSha256()\n    {\n        return new \\Lcobucci\\JWT\\Signer\\Hmac\\Sha256();\n    }\n\n    /**\n     * @return Token created token\n     */\n    public function createTokenWithSignature()\n    {\n        return $this->jwt->getBuilder()->setIssuer(self::ISSUER) // Configures the issuer (iss claim)\n                ->setAudience(self::AUDIENCE) // Configures the audience (aud claim)\n                ->setId(self::ID, true) // Configures the id (jti claim), replicating as a header item\n                ->setIssuedAt(time()) // Configures the time that the token was issue (iat claim)\n                ->setExpiration(time() + 3600) // Configures the expiration time of the token (nbf claim)\n                ->set('uid', 1) // Configures a new claim, called \"uid\"\n                ->sign($this->getSignerSha256(), $this->jwt->key) // creates a signature using \"testing\" as key\n                ->getToken(); // Retrieves the generated token\n    }\n    \n    /**\n     * @return ValidationData\n     */\n    public function getValidationData()\n    {\n        $data = $this->jwt->getValidationData(); // It will use the current time to validate (iat, nbf and exp)\n        $data->setIssuer(self::ISSUER);\n        $data->setAudience(self::AUDIENCE);\n        $data->setId(self::ID);\n        return $data;\n    }\n\n    /**\n     * Validate token with signature\n     */\n    public function testValidateTokenWithSignature()\n    {\n        $token = $this->createTokenWithSignature();\n        $data = $this->getValidationData();\n        $is_verify = $token->verify($this->getSignerSha256(), $this->jwt->key);\n        $is_valid = $token->validate($data); // true, because validation information is equals to data contained on the token\n        $this->assertTrue($is_verify && $is_valid);\n    }\n    \n    /**\n     * Validate token timeout with signature\n     */\n    public function testValidateTokenTimeoutWithSignature()\n    {\n        $token = $this->createTokenWithSignature();\n        $data = $this->getValidationData();\n        $data->setCurrentTime(time() + 4000); // changing the validation time to future\n        $is_verify = $token->verify($this->getSignerSha256(), $this->jwt->key);\n        $is_valid = $token->validate($data); // false, because token is expired since current time is greater than exp\n        $this->assertFalse($is_verify && $is_valid);\n    }\n}\n"
  },
  {
    "path": "tests/TestCase.php",
    "content": "<?php\n\nnamespace sizeg\\jwt\\tests;\n\nuse yii\\console\\Application;\n\n/**\n * Class TestCase\n * @author SiZE\n */\nclass TestCase extends \\PHPUnit_Framework_TestCase\n{\n\n    /**\n     * @inheritdoc\n     */\n    protected function setUp()\n    {\n        parent::setUp();\n        $this->mockApplication();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function tearDown()\n    {\n        $this->destroyApplication();\n        parent::tearDown();\n    }\n\n    protected function mockApplication()\n    {\n        new Application([\n            'id' => 'testapp',\n            'basePath' => __DIR__,\n            'vendorPath' => dirname(__DIR__) . '/vendor',\n            'runtimePath' => __DIR__ . '/runtime',\n        ]);\n    }\n\n    protected function destroyApplication()\n    {\n        \\Yii::$app = null;\n    }\n}"
  },
  {
    "path": "tests/bootstrap.php",
    "content": "<?php\n \ndefined('YII_DEBUG') or define('YII_DEBUG', true);\ndefined('YII_ENV') or define('YII_ENV', 'test');\n \nrequire(__DIR__ . '/../vendor/autoload.php');\nrequire(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');"
  }
]