{"id":25963449,"url":"https://github.com/yivi/yivoffjwtrefreshbundle","last_synced_at":"2025-03-04T20:38:41.053Z","repository":{"id":56454723,"uuid":"260959009","full_name":"yivi/YivoffJwtRefreshBundle","owner":"yivi","description":"Provides a way to refresh a JWT (JSON Web Token) as provided by Lexik JWT Authentication Bundle","archived":false,"fork":false,"pushed_at":"2025-01-22T14:59:08.000Z","size":258,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-24T08:57:22.792Z","etag":null,"topics":["authentication","jwt","php","symfony-5","symfony-bundle"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yivi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-03T15:25:31.000Z","updated_at":"2025-01-22T14:59:12.000Z","dependencies_parsed_at":"2022-08-15T19:01:04.959Z","dependency_job_id":null,"html_url":"https://github.com/yivi/YivoffJwtRefreshBundle","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yivi%2FYivoffJwtRefreshBundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yivi%2FYivoffJwtRefreshBundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yivi%2FYivoffJwtRefreshBundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yivi%2FYivoffJwtRefreshBundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yivi","download_url":"https://codeload.github.com/yivi/YivoffJwtRefreshBundle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241921221,"owners_count":20042761,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","jwt","php","symfony-5","symfony-bundle"],"created_at":"2025-03-04T20:38:40.235Z","updated_at":"2025-03-04T20:38:41.040Z","avatar_url":"https://github.com/yivi.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# yivoff/jwt-refresh-bundle\n\n[![PHP Version Require](http://poser.pugx.org/yivoff/jwt-refresh-bundle/require/php)](https://packagist.org/packages/yivoff/jwt-refresh-bundle)\n[![Latest Stable Version](http://poser.pugx.org/yivoff/jwt-refresh-bundle/v)](https://packagist.org/packages/yivoff/jwt-refresh-bundle)\n[![Total Downloads](http://poser.pugx.org/yivoff/jwt-refresh-bundle/downloads)](https://packagist.org/packages/yivoff/jwt-refresh-bundle)\n[![Latest Unstable Version](http://poser.pugx.org/yivoff/jwt-refresh-bundle/v/unstable)](https://packagist.org/packages/yivoff/jwt-refresh-bundle)\n[![License](http://poser.pugx.org/yivoff/jwt-refresh-bundle/license)](https://packagist.org/packages/yivoff/jwt-refresh-bundle)\n![Tests](https://github.com/yivi/YivoffJwtRefreshBundle/actions/workflows/bundle_tests.yaml/badge.svg)\n[![codecov](https://codecov.io/gh/yivi/YivoffJwtRefreshBundle/branch/master/graph/badge.svg?token=4JDTQ4IDN7)](https://app.codecov.io/gh/yivi/YivoffJwtRefreshBundle)\n\n* [Description](#description)\n* [Requirements](#requirements)\n* [Installation and setup](#installation-and-setup)\n  * [Installation](#installation)\n  * [Token Provider Implementation](#token-provider-implementation)\n    * [Purgable Provider](#purgable-provider)\n  * [Security Integration](#security-integration) \n  * [Bundle Configuration](#bundle-configuration)\n  * [Purge Command](#purge-command)\n* [Usage](#usage)\n\n## Description \n\nThis package provides a way to generate \"refresh tokens\" that users can use to obtain a new authorization token (JWT)\nwhen the previous one expires. This is a companion for [lexik/LexikJWTAuthenticationBundle], and it is not usable on its\nown.\n\nThe package does not make any assumptions about the persistence layer for storing the refresh tokens. You can use any\nbackend or library (Mysql, Mongo, Redis, flat-file, etc) as long as there is a service that implements a basic interface\nprovided by the package: [`RefreshTokenProviderInterface`][1]\n\nTokens are stored with an identifier and a hashed verifier, instead of a plain-text verifier, for added security.\n\nEach refresh-token can only be used once to get a new auth-token. When used, the old refresh-token is deleted, and a new\nrefresh-token is generated.\n\nYou should setup the time-to-live for the refresh-tokens to be significantly higher than the time to live of the\nauth-tokens. \n\n## Requirements\n\nRequires PHP 8+, Symfony 5.3+\n\n## Installation and Setup\n\n### Installation \n```bash\n$ composer require yivoff/jwt-refresh-bundle\n```\n### Token Provider Implementation\n\nThis package makes no assumptions about the nature of your token provider. To be able to use it you'll need to implement\nyour own, either a regular Doctrime ORM repository or whatever better suits your project.\n\nYou'll need to have a service that implements `RefreshTokenProviderInterface`, and then on the bundle configuration, on\n`yivoff_jwt_refresh.token_provider_service` you'll write down the service ID that the bundle will use for\ngetting/adding/removing tokens.\n\nThis service is responsible, directly or indirectly, of mediating with your persistance layer of choice, and  should\nreturn/accept [`RefreshTokenInterface`][2] instances. Either your application token entity implements this interface\ndirectly, or your token-provider adapts between your native entities, and the provided [`RefreshToken`][3] class.\n\n#### Purgable Provider\n\nYour token provider can additionally implement `PurgableRefreshTokenProviderInterface`, to have a convenience method to \nclear up all the stale tokens. This is necessary if you want to use the included [purge command](#purge-command)\n\n### Security integration\n\nOn the same firewall where the JWT Authenticator provides with a login check, setup a new guard authenticator provided\nby this bundle (`Yivoff\\JwtTokenRefresh\\Security\\Authenticator`).\n\nE.g, for a typical configuration:\n\n```yaml\nfirewalls:\n    login:\n        pattern:  ^/login\n        stateless: true\n        anonymous: true\n        provider: users_in_memory\n        custom_authenticators:\n          - Yivoff\\JwtTokenRefresh\\Security\\Authenticator\n        json_login:\n            check_path:               /login_check\n            success_handler:          lexik_jwt_authentication.handler.authentication_success\n            failure_handler:          lexik_jwt_authentication.handler.authentication_failure \n```\n\nNotice the content for `firewall.login.guard.authenticators`.\n\n### Bundle Configuration:\n**Yaml**\n```yaml\nyivoff_jwt_refresh:\n    token_provider_service: 'App\\Repository\\AuthRefreshTokenRepository'\n    token_ttl: 3600\n    parameter_name: 'refresh_token'\n```\n\n**XML**\n```xml\n\u003cyivoff_jwt_refresh xmlns=\"https://yivoff.com/schema/dic/jwt_refresh_bundle\"\u003e\n    \u003cprovider_service\u003eApp\\Infrastructure\\Redis\\Repository\\AuthRefreshTokenRepository\u003c/provider_service\u003e\n    \u003cparameter_name\u003erefresh_token\u003c/parameter_name\u003e\n    \u003ctoken_ttl\u003e3600\u003c/token_ttl\u003e\n\u003c/yivoff_jwt_refresh\u003e\n```\n\n* `token_provider_service` \n\n   This is a **required** key. The string value must be the _id_ for a service that implements\n`RefreshTokenProviderInterface`.\n\n* `token_ttl`\n\n   The bundle provides a default value of 3600. Change it if you want the token to be available for more or less time.\n\n* `parameter_name`\n\n    Name of the HTTP `POST` parameter that will hold the refresh token. `refresh_token` by default.\n\n### Purge command\nIf `symfony/console` is installed on your project, and your Token Provider implements\n`PurgableRefreshTokenProviderInterface`, you can use a command to delete all the existing tokens that have already\nexpired.\n\nThe command can simply be executed by running `bin/console yivoff:jwt_refresh:purge_expired_tokens`. On non-error\nconditions, it produces no output.\n\n### Usage\n\nOn any regular JSON authentication, the bundle will inject a refresh token on a field named as the `parameter_name`\ndefined on the configuration. A typical request/response would be:\n\n**Request**\n```http request\nPOST http://localhost:7099/login_check\nContent-Type: application/json\n\n{\n  \"username\": \"john_user\",\n  \"password\": \"abcd\"\n}\n```\n**Response**\n```http request\nHTTP/1.1 200 OK\nDate: Sat, 09 May 2020 16:01:37 GMT\nConnection: close\nContent-Type: application/json\n\n{\n  \"token\": \"ey...token...131\",\n  \"refresh_token\": \"bd8b1a304dc39dda3d10a38788b2ebf7:f52ac998773d552a0c639c2f85ffa5f2e18df2f1a3f528c9ddc3fcd8c6ba2f31\"\n}\n```\n\nIt is not necessary to register a new route for the \"refresh\" path. To get a new authentication JWT, you simply call the\nsame login path with regular `POST` call with a HTTP parameter with the same name and value that we received previously:\n\n```http request\nPOST http://localhost:7099/login_check\nContent-Type: application/x-www-form-urlencoded\n\nrefresh_token=bd8b1a304dc39dda3d10a38788b2ebf7:f52ac998773d552a0c639c2f85ffa5f2e18df2f1a3f528c9ddc3fcd8c6ba2f31\n```\n### Events\n\nIf you want your application to react to successful or failed refresh attempts (logging, etc.), the library emits events\nthat you can listen to.\n\n#### Failure\n\nWhen the refresh attempt fails for whatever reason, the library emits a `Yivoff\\JwtRefreshBundle\\Event\\JwtRefreshTokenFailed`\nevent. \n\nThe event has three public properties:\n\n* `?string tokenId`: The identifier for the refresh token. This will be null if the payload was invalid, and no\n   identifier could be retrieved from the request.\n* `?string userIdentifier`: The identifier for the user that ows the token. this will be null if the payload was\n   invalid, or if we couldn't find a token for the request `tokenId`.\n* `FailType $failType`: This is an enum that describes the failure type encountered:\n  * `FailType::PAYLOAD`: Payload could not be parsed.\n  * `FailType::NOT_FOUND`: Token by this id could not be found.\n  * `FailType::INVALID`:  Token was found, but verifier was invalid.\n  * `FailType::EXPIRED`: Token was found, but it was already expired.\n\n#### Success\n\nOn success, a `Yivoff\\JwtRefreshBundle\\Event\\JwtRefreshTokenSucceeded` event is emitted. This simply includes the\nproperties:\n\n* `string tokenId`: the identifier for the refresh token\n* `string userIdentifier`: the identifier for the user that owns the token\n\n[1]: https://github.com/yivi/YivoffJwtRefreshBundle/blob/master/Contracts/RefreshTokenProviderInterface.php\n[2]: https://github.com/yivi/YivoffJwtRefreshBundle/blob/master/Contracts/RefreshTokenInterface.php\n[3]: https://github.com/yivi/YivoffJwtRefreshBundle/blob/master/Model/RefreshToken.php\n[4]: https://github.com/lexik/LexikJWTAuthenticationBundle\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyivi%2Fyivoffjwtrefreshbundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyivi%2Fyivoffjwtrefreshbundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyivi%2Fyivoffjwtrefreshbundle/lists"}