Implements a Refresh Token system over Json Web Tokens in Symfony

Overview

JWTRefreshTokenBundle

Scrutinizer Code Quality Run Tests Code Coverage Latest Stable Version Total Downloads License StyleCI

The purpose of this bundle is manage refresh tokens with JWT (Json Web Tokens) in an easy way. This bundles uses LexikJWTAuthenticationBundle. Supports Doctrine ORM/ODM.

Prerequisites

This bundle requires PHP 7.4 or later and Symfony 3.4, 4.4, or 5.2+.

If you want to use this bundle with previous Symfony versions, please use 0.2.x releases.

Protip: Though the bundle doesn't force you to do so, it is highly recommended to use HTTPS.

Installation

Step 1: Download the Bundle

It's important you manually require either Doctrine's ORM or MongoDB ODM as well, these packages are not required automatically as you can choose between them. Failing to do so may trigger errors on installation

With Doctrine's ORM

composer require doctrine/orm doctrine/doctrine-bundle gesdinet/jwt-refresh-token-bundle

With Doctrine's MongoDB ODM

composer require doctrine/mongodb-odm-bundle gesdinet/jwt-refresh-token-bundle

or edit composer.json:

{
  "require": {
    "doctrine/doctrine-bundle": "^1.12 || ^2.0",
    "doctrine/mongodb-odm-bundle": "^3.4 || ^4.0",
    "doctrine/orm": "^2.7",
    "gesdinet/jwt-refresh-token-bundle": "^1.0"
  }
}

Alternatively, a custom persistence layer can be used.

For that purpose:

Step 2: Enable the Bundle

Symfony Flex Application

For an application using Symfony Flex the bundle should be automatically registered, but if not you will need to add it to your config/bundles.php file.

<?php

return [
    //...
    Gesdinet\JWTRefreshTokenBundle\GesdinetJWTRefreshTokenBundle::class => ['all' => true],
];

Symfony Standard Application

For an application based on the Symfony Standard structure, you will need to add the bundle to your AppKernel class' registerBundles() method.

<?php

use Symfony\Component\HttpKernel\Kernel;

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = [
            // ...
            new Gesdinet\JWTRefreshTokenBundle\GesdinetJWTRefreshTokenBundle(),
        ];
    }
}

Step 3 (Symfony 5.3+)

Define the refresh token route

Open your routing configuration file and add the following route to it:

# app/config/routing.yml or config/routes.yaml
gesdinet_jwt_refresh_token:
    path: /api/token/refresh
# ...

Configure the authenticator

Add the below to your security configuration file:

# app/config/security.yml or config/packages/security.yaml
security:
    enable_authenticator_manager: true

    firewalls:
        # put it before all your other firewall API entries
        api_token_refresh:
            pattern: ^/api/token/refresh
            stateless: true
            refresh_jwt: ~
    # ...

    access_control:
        # ...
        - { path: ^/api/token/refresh, roles: PUBLIC_ACCESS }
        # ...
# ...

Step 3 (Symfony 5.2-)

Define the refresh token route

Open your routing configuration file and add the following route to it:

Symfony 3 Version:

# app/config/routing.yml
gesdinet_jwt_refresh_token:
    path:     /api/token/refresh
    defaults: { _controller: gesdinet.jwtrefreshtoken:refresh }
# ...

Symfony 4 Version:

# config/routes.yaml
gesdinet_jwt_refresh_token:
    path:       /api/token/refresh
    controller: gesdinet.jwtrefreshtoken::refresh
# ...

Configure the security firewall

Add the below to your security configuration file:

# app/config/security.yml or config/packages/security.yaml
security:
    firewalls:
        # put it before all your other firewall API entries
        refresh:
            pattern:  ^/api/token/refresh
            stateless: true
            anonymous: true
    # ...

    access_control:
        # ...
        - { path: ^/api/token/refresh, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        # ...
# ...

Step 4: Update your database schema

With the next commands you will add the table to store your refresh tokens to your database

php bin/console doctrine:schema:update --force

# or make and run a migration:
php bin/console make:migration
php bin/console doctrine:migrations:migrate

Usage

The below configurations can be put in the following files, depending on the Symfony version you are running:

Symfony 3 Version: app/config/config.yml
Symfony 4 Version: config/packages/gesdinet_jwt_refresh_token.yaml

Token TTL

You can define the refresh token TTL, this value is set in seconds and defaults to 1 month. You can change this value adding this line to your config:

gesdinet_jwt_refresh_token:
    ttl: 2592000

Update Token TTL

You can configure the bundle to refresh the TTL on a refresh token when it is used, by default this feature is disabled. You can change this value adding this line to your config:

gesdinet_jwt_refresh_token:
    ttl_update: true

Config Firewall Name

NOTE This setting is deprecated and is not used with the refresh_jwt authenticator

You can define Firewall name. Default value is api. You can change this value adding this line to your config:

gesdinet_jwt_refresh_token:
    firewall: api

Refresh Token Parameter Name

You can define the parameter name for the refresh token when it is read from the request, the default value is refresh_token. You can change this value adding this line to your config:

gesdinet_jwt_refresh_token:
    token_parameter_name: refreshToken

Set The User Provider

Symfony 5.3+

You can define a user provider to use for the authenticator its configuration:

# app/config/security.yml or config/packages/security.yaml
security:
    firewalls:
        api_token_refresh:
            pattern: ^/api/token/refresh
            stateless: true
            refresh_jwt:
                provider: user_provider_service_id

By default, when a user provider is not specified, then the user provider for the firewall is used instead.

Symfony 5.2-

NOTE This setting is deprecated and is not used with the refresh_jwt authenticator

You can define your own user provider, by default the gesdinet.jwtrefreshtoken.user_provider service is used. You can change this value by adding this line to your config:

gesdinet_jwt_refresh_token:
    user_provider: user_provider_service_id

For example, if you are using FOSUserBundle, user_provider must be set to fos_user.user_provider.username_email.

For Doctrine ORM UserProvider, user_provider must be set to security.user.provider.concrete.<your_user_provider_name_in_security_yaml>.

For example, in your app/config/security.yml or config/packages/security.yaml:

security:
    # ...
    providers:
        app_user_provider:
            # ...
    firewalls:
    # ...
# ...

then your user_provider_service_id is security.user.provider.concrete.app_user_provider.

Doctrine Manager Type

By default, this bundle sets the Doctrine Manager type to the ORM. If you want to use Doctrine's MongoDB ODM you have to change this value:

gesdinet_jwt_refresh_token:
    manager_type: mongodb

Set The User Checker

Symfony 5.3+

You can define a user checker to use for the firewall as part of the firewall configuration:

# app/config/security.yml or config/packages/security.yaml
security:
    firewalls:
        api_token_refresh:
            pattern: ^/api/token/refresh
            stateless: true
            user_checker: user_checker_service_id
            refresh_jwt: ~

Symfony 5.2-

NOTE This setting is deprecated and is not used with the refresh_jwt authenticator

You can define your own user checker, by default the security.user_checker service is used. You can change this value by adding this line to your config:

gesdinet_jwt_refresh_token:
    user_checker: user_checker_service_id

You will probably want to use a custom user provider along with your user checker to ensure that the checker receives the right type of user.

Single Use Tokens

You can configure the refresh token so it can only be consumed once. If set to true and the refresh token is consumed, a new refresh token will be provided.

To enable this behavior add this line to your config:

gesdinet_jwt_refresh_token:
    single_use: true

Configure refresh token in cookie

By default, the refresh token is returned in a JsonResponse. You can use the following configuration to set it in a HttpOnly cookie instead. The refresh token is automatically extracted from the cookie during refresh.

gesdinet_jwt_refresh_token:
    cookie:
      enabled: true
      same_site: lax               # default value
      path: /                      # default value
      domain: null                 # default value
      http_only: true              # default value
      secure: true                 # default value
      remove_token_from_body: true # default value

Use another entity for refresh tokens

You can define your own refresh token class on your project.

When using the Doctrine ORM, create a class extending Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken in your application:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken;

/**
 * This class extends Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken to have another table name.
 *
 * @ORM\Table("jwt_refresh_token")
 */
class JwtRefreshToken extends RefreshToken
{
}

When using the Doctrine MongoDB ODM, create a class extending Gesdinet\JWTRefreshTokenBundle\Document\RefreshToken in your application:

<?php

namespace App\Document;

use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Gesdinet\JWTRefreshTokenBundle\Document\RefreshToken;

/**
 * This class extends Gesdinet\JWTRefreshTokenBundle\Document\RefreshToken to have another collection name.
 *
 * @MongoDB\Document(collection="jwt_refresh_token")
 */
class JwtRefreshToken extends RefreshToken
{
}

Then declare this class adding this line to your config.yml file:

gesdinet_jwt_refresh_token:
    refresh_token_class: App\Entity\JwtRefreshToken

Use another object manager

You can configure the bundle to use any object manager, just add this line to your config.yml file:

gesdinet_jwt_refresh_token:
    object_manager: my.specific.entity_manager.id

Disable automatic Doctrine mappings

NOTE This setting is deprecated and is no longer used

On some occasions, you may not want to have default Doctrine mappings of object manager enabled as you use neither ORM nor ODM but i.e. using DoctrineBundle for DBAL.

To disable dynamic Doctrine mapping add this line to your config:

gesdinet_jwt_refresh_token:
    doctrine_mappings: false

Generating Tokens

When you authenticate through /api/login_check with user/password credentials, LexikJWTAuthenticationBundle now returns a JWT Token and a Refresh Token data.

{
  "token": "eyxxxGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJleHAiOjE0NDI0MDM3NTgsImVtYWlsIjoid2VibWFzdGVyQGdlc2RpbmV0LmNvbSIsImlhdCI6IjE0NDI0MDM3MzgifQ.bo5pre_v0moCXVOZOj-s85gVnBLzdSdsltPn3XrkmJaE8eaBo_zcU2pnjs4dUc9hhwNZK8PL6SmSNcQuTUj4OMK7sUDfXr62a05Ds-UgQP8B2Kpc-ZOmSts_vhgo6xJNCy8Oub9-pRA_78WzUUxt294w0IArrNlgQAGewk65RSMThOif9G6L7HzBM4ajFZ-kMDypz2zVQea1kry-m-XXKNDbERCSHnMeV3rANN48SX645_WEvwaHy0agChR4hTnThzLof2bShA7j7HmnSPpODxQszS5ZBHdMgTvYhlcWJmwYswCWCTPl3lsqVq_UOFI5_4arpSNlUwZsichqxXVAHX5idZqCWtoaqAbvNQe2IpinYajoXw-MlYKvcN2TLUF_8sy529olLUagf4FCpCO6JFxovv0E7ll9tUOVvx9LlannqV8976q5XCOoXszKonZSH7DhsBlW5Emjv7PailbARZ-hfl4YlamyY2QbnxAswYycfoxqJxbbIKYGA8dlebdvMyC7m9VATnasTuKeEKS3mP5iyDgWALBHNYXm1FM-12zHBdN3PbOgxmy_OBGvk05thYFEf2WVmyedtFHy4TGlI0-otUTAf2swQAXWhKtkLWzokWWF7l5iNzam1kkEgql5EOztXHDZpmdKVHWBVNvN3J5ivPjjJBm6sGusf-radcw",
  "refresh_token": "xxx00a7a9e970f9bbe076e05743e00648908c38366c551a8cdf524ba424fc3e520988f6320a54989bbe85931ffe1bfcc63e33fd8b45d58564039943bfbd8dxxx"
}

The refresh token is persisted as a RefreshTokenInterface object. After that, when your JWT valid token expires, if you want to get a new one you can proceed in two ways:

  • Send you user credentials again to /api/login_check. This generates another JWT with another Refresh Token.
  • Ask to renew valid JWT with our refresh token. Make a POST call to /api/token/refresh url with refresh token as payload. In this way, you can always get a valid JWT without asking for user credentials. But you must check if the refresh token is still valid. Your refresh token will not change but its TTL will increase.

Note that when a refresh token is consumed and the config option single_use is set to true the token will no longer be valid.

curl -X POST -d refresh_token="xxxx4b54b0076d2fcc5a51a6e60c0fb83b0bc90b47e2c886accb70850795fb311973c9d101fa0111f12eec739db063ec09d7dd79331e3148f5fc6e9cb362xxxx" 'http://xxxx/token/refresh'

This call returns a new valid JWT token renewing valid datetime of your refresh token.

Useful Commands

We give you two commands to manage tokens.

Revoke all invalid tokens

If you want to revoke all invalid (datetime expired) refresh tokens you can execute:

php bin/console gesdinet:jwt:clear

The command optionally accepts a date argument which will delete all tokens older than the given time. This can be any value that can be parsed by the DateTime class.

php bin/console gesdinet:jwt:clear 2015-08-08

We recommend executing this command as a cronjob to remove invalid refresh tokens on an interval.

Revoke a token

If you want to revoke a single token you can use this command:

php bin/console gesdinet:jwt:revoke TOKEN

Events

If you want to do something when token is refreshed you can listen for gesdinet.refresh_token event.

For example:

<?php

namespace App\EventListener;

use Gesdinet\JWTRefreshTokenBundle\Event\RefreshEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class LogListener implements EventSubscriberInterface
{
    private $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public function log(RefreshEvent $event)
    {
        $refreshToken = $event->getRefreshToken()->getRefreshToken();
        $user = $event->getToken()->getUser()->getUsername();
        
        $this->logger->debug(sprintf('User "%s" has refreshed it\'s JWT token with refresh token "%s".', $user, $refreshToken));
    }
    
    public static function getSubscribedEvents()
    {
        return array(
            'gesdinet.refresh_token' => 'log',
        );
    }
}

Token Extractor

The bundle provides a Gesdinet\JWTRefreshTokenBundle\Request\Extractor\ExtractorInterface to define classes which can read the refresh token from the request.

By default, the Gesdinet\JWTRefreshTokenBundle\Request\Extractor\ChainExtractor is used which allows checking multiple aspects of the request for a token. The first token found will be used.

You can create a custom extractor by adding a class to your application implementing the interface. For example, to add an extractor checking for a "X-Refresh-Token" header:

<?php

namespace App\Request\Extractor;

use Gesdinet\JWTRefreshTokenBundle\Request\Extractor\ExtractorInterface;
use Symfony\Component\HttpFoundation\Request;

final class HeaderExtractor implements ExtractorInterface
{
    public function getRefreshToken(Request $request, string $parameter): ?string
    {
        return $request->headers->get('X-Refresh-Token');
    }
}

This bundle handles automatically configuring ExtractorInterface objects and will automatically set the gesdinet_jwt_refresh_token.request_extractor container tag when your application uses autoconfiguration (autoconfigure: true in your services.yaml file). If autoconfiguration is not in use, you will need to manually configure the tag:

services:
    App\Request\Extractor\HeaderExtractor:
        tags:
            - { name: gesdinet_jwt_refresh_token.request_extractor }

Prioritizing Extractors

The gesdinet_jwt_refresh_token.request_extractor container tag supports prioritizing extractors, you can use this to set the preferred order for your extractors by adding a priority attribute. The higher the number, the sooner the extractor will be run.

services:
    App\Request\Extractor\HeaderExtractor:
        tags:
            - { name: gesdinet_jwt_refresh_token.request_extractor, priority: 25 }
Comments
  • Error in RefreshTokenManager - Support for doctrine/common +3.0

    Error in RefreshTokenManager - Support for doctrine/common +3.0

    Since Doctrine Common 3.0, Common was split into smaller packages.

    Actually in RefreshTokenManager you inject Doctrine\Common\Persistence\ObjectManager in constructor.

    Since Doctrine Common 3.0, Doctrine\Common\Persistence\ObjectManager became Doctrine\Persistence\ObjectManager.

    opened by HeiJon 25
  • Support for refresh token in cookie

    Support for refresh token in cookie

    Hi @markitosgv

    I created support for refresh token in cookie. Cookie is also automatically extracted. Cookie is by default httpOnly, thus cannot be read by JS and it's safe against XSS attack.

    opened by lukacovicadam 17
  • refresh token with additional fields in payload

    refresh token with additional fields in payload

    Hello, I'm new in symfony and and try to set HWTRefreshTokenBundle with JTW Lexik. In jwt I have own Entity

    namespace SharedBundle\Security;
    
    final class User implements \Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUserInterface
    {
        private $username;
        private $roles;
        private $name;
        
        public function __construct($username, array $roles, $email, $name)
        {
            $this->username = $username;
            $this->roles = $roles;
            $this->email = $email;
            $this->name = $name;
        }
        
        public static function createFromPayload($username, array $payload)
        {
            return new self(
                $username,
                $payload['roles'], // Added by default
                $payload['email'],  // Custom
                $payload['name']
            );
        }
    
     /**
         * {@inheritdoc}
         */
        public function getUsername()
        {
            return $this->username;
        }
        /**
         * {@inheritdoc}
         */
        public function getName()
        {
            return $this->name;
        }
        /**
         * {@inheritdoc}
         */
        public function getRoles()
        {
            return $this->roles;
        }
     ...
    

    In listener I add custom data:

    public function onJWTCreated(JWTCreatedEvent $event) {
        $request = $this->requestStack->getCurrentRequest();
    
        $payload = $event->getData();
        $user = $event->getUser();
        
        $payload['name'] = $user->getName();
        $payload['email'] = $user->getEmail();
        $payload['ip'] = $request->getClientIp();
    
        $event->setData($payload);
      }
    

    But when I try to refresh token I get error:

    [Mon May 29 22:07:36 2017] 127.0.0.1:56078 [200]: /api/token/refresh
    [Mon May 29 22:13:52 2017] PHP Fatal error:  Call to undefined method Symfony\Component\Security\Core\User\User::getName() in .../application/be/src/SharedBundle/EventListener/JWTCreatedListener.php on line 33
    Segmentation fault
    

    When I throw email and name from payload token is created but without this data, and return only default role ROLE_USER without ROLE_ADMIN.

    I'tried to use refresh_token_entity: SharedBundle\Security\User but without result :/ How can I implemet additional fields in payload?

    opened by nicraMarcin 11
  • Class gesdinet.jwtrefreshtoken does not exist.

    Class gesdinet.jwtrefreshtoken does not exist.

    I get refresh token but when I call jwt refresh path response is 500 (Class gesdinet.jwtrefreshtoken does not exist. (500 Internal Server Error)) composer.json

    `"require"` : {
    		"php" : ">=7.1",
    		"symfony/symfony" : "3.4.*",
    		"doctrine/orm" : "^2.5",
    		"doctrine/doctrine-bundle" : "^1.6",
    		"doctrine/doctrine-cache-bundle" : "^1.3",
    		....
                    "lexik/jwt-authentication-bundle": "^2.4",
    		"gesdinet/jwt-refresh-token-bundle": "^0.5.2"
    	},`
    
    the configuration is identical to the documentation, anyone can help?
    
    opened by maciejkosiarski 10
  • UX with cookie-based refresh tokens

    UX with cookie-based refresh tokens

    Hello there! 👋

    I've been testing the "cookie" option of this bundle, lately. This is awesome and it works great! 🎉 It avoids having to store the token on the client side and expose it to creepy people.

    However, I notice 2 usability issues with this:

    1. When the user logs out from the SPA, client just destroys the access token and the user gets redirected to the login page. Fine. problem is, since client has not access to the refreshToken anymore, it can no longer destroy it. This means that next call to the refresh token route will log the user in, even if they wanted to logout, because the cookie is still here 😓

    2. Since the refreshToken is no longer the client's business, 2 different users can't be logged in within the same browser. I usually have an "admin" tab and a "customer" tab. Since both share the same cookie (same API), as soon as I sign in as a customer, I get kicked from the admin tab once this one asks for a new token.

    Regarding 1: how about the following flow:

    # Refresh current token
    POST /api/token/refresh
    Cookie: refreshToken=myCurrentRefreshToken
    
    HTTP/2 200 OK
    Set-Cookie: refreshToken=someOtherRefreshToken, expires=in one week
    
    # Revoke that token
    DELETE /api/token/refresh
    Cookie: refreshToken=someOtherRefreshToken
    
    HTTP/2 200 OK
    Set-Cookie: refreshToken=, expires=right now
    

    Regarding 2... I have no real idea on how to address this. Thoughts?

    opened by bpolaszek 8
  • does not work in Symfony 4.3 but does in 4.2 - doctrine .yml problem?

    does not work in Symfony 4.3 but does in 4.2 - doctrine .yml problem?

    When upgrading from Symfony 4.2 to 4.3, the mappings did not work correctly anymore and I got errors like 'Property "refreshToken" does not exist in class "Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken"'

    Downgrading the refresh token bundle to v0.3.3 seems to work fine

    It seems doctrine .yml mappings will be deprecated, see: https://github.com/doctrine/DoctrineBundle/issues/776 maybe that's the cause? (the downgraded bundle still uses annotations)

    opened by 24HOURSMEDIA 8
  • Security issue: Loadable users are always authenticated

    Security issue: Loadable users are always authenticated

    The current implementation to refresh JWT tokens is not safe. When a user presents a refresh token, the only check that occurs is whether the user provider can load the user. If a user is loadable, it is granted a new access token.

    But the authenticator should also check if the loaded user is still allowed to access the application. For example, users that implement the AdvancedUserInterface should be checked whether their account is enabled, is not locked and is not expired. Other means of authentication may have other requirements (e.g. for OAuth accounts, check whether the correct permissions are still present).

    Currently, this bundle will happily give out new access tokens to users who have been disabled, expired, etc.

    I think there should be some way to hook into the authenticator to provide this logic. Or perhaps the authenticator in this bundle should delegate authentication to some other authentication provider.

    Currently I am using a compiler pass to overwrite the authenticator provided in this bundle with my own. That's a bit of a hackish solution.

    opened by sandermarechal 8
  • Symfony 6 - dependency problem

    Symfony 6 - dependency problem

    The latest release 1.0 is showing problem in Symfony 6.0 dependency.

    gesdinet/jwt-refresh-token-bundle v1.0.0 requires symfony/deprecation-contracts ^2.1 -> found symfony/deprecation-contracts[v2.1.0, ..., v2.5.0] but the package is fixed to v3.0.0 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.

    image

    opened by ajay-gupta 7
  • how to auto refresh when the token expired?

    how to auto refresh when the token expired?

    I want refresh the token by token or refresh_token if token is expired.but symfony not has any middleware like laravel.So,if token is expired ,it will dispatch a event named JWTExpiredEvent and return a response from that event.But how to return the old response like /users/me,/articles/create after I refresh_token in JWTExpiredEvent event? Not by send refresh token uri by frontend My code

      public function onJWTExpired(JWTExpiredEvent $event)
        {
            $event->setResponse($this->autoRefreshToken($event, [
                'code' => '50008',
                'message' => self::$errorMessages['error-token']
            ]));
        }
        protected function autoRefreshToken(JWTFailureEventInterface $event, $errorData = [])
        {
            $encoder = new JsonEncoder();
            $errorData['code'] = $errorData['code'] ?? 50002;
            $errorData['message'] = $errorData['message'] ?? 'Bad credentials.';
            /** @var JWTAuthenticationFailureResponse $response */
            $response = $event->getResponse();
            $this->setRefreshTokenFromRequestHeaders($encoder);
            /** @var JWTAuthenticationSuccessResponse|JWTAuthenticationFailureResponse $result */
            $result = $this->RefreshToken->refresh($this->request);
    
            if ($result instanceof JWTAuthenticationSuccessResponse) {
                // Here I want to return the response of 'users/me'
                // And add the token info by `$result->getContent()` to response header
                // How to do it?
            }
            $response->setData($errorData);
            return $response;
        }
    
        protected function setRefreshTokenFromRequestHeaders(JsonEncoder $jsonEncoder)
        {
            if ($this->request->headers->has('Refresh-Token')) {
                $RefreshToken = $this->request->headers->get('Refresh-Token');
                if (false !== strpos($this->request->getContentType(), 'json')) {
                    $params = !empty($content) ? $jsonEncoder->decode($content,'json') : array();
                    $params['refresh_token'] = isset($params['refresh_token']) ? trim($params['refresh_token']) : $RefreshToken;
                    $this->request->initialize(
                        $this->request->query->all(),
                        $this->request->request->all(),
                        $this->request->attributes->all(),
                        $this->request->cookies->all(),
                        $this->request->files->all(),
                        $this->request->server->all(),
                        $jsonEncoder->encode($params,'json')
                    );
                } else {
                    $this->request->attributes->set('refresh_token', $RefreshToken);
                }
            }
        }
    

    How to do it?please Help me,thx!

    opened by lichnow 7
  • Possible to Use Chained User Provider ?

    Possible to Use Chained User Provider ?

    Is it possible to use a chained user provider? E.g. A couple of default users in memory and some from FosUserBundle ?

    Not a huge deal as I can just load those in as fixtures, but I was just curious because the user provider needs to be defined as a service ID it seems.

    opened by silverbackdan 7
  • Neither the property email nor ... exist and have public access in class Symfony Core User

    Neither the property email nor ... exist and have public access in class Symfony Core User

    Hi,

    After installing and configuring JWTRefreshTokenBundle successfully, I have this error when I try to do the curl request:

    curl -X POST -d refresh_token="xxxx4b54b0076d2fcc5a51a6e60c0fb83b0bc90b47e2c886accb70850795fb311973c9d101fa0111f12eec739db063ec09d7dd79331e3148f5fc6e9cb362xxxx" 'http://xxxx/token/refresh'
    

    The error:

    Neither the property "email" nor one of the methods "getEmail()", "email()", "ismail()", "hasEmail()", "__get()" exist and have public access in class "Symfony\\Component\\Security\\Core\\User\\User"
    

    I used FOSUserBundle with LexikJWTAuthenticationBundle. Maybe I have to configure the user provider of this bundle but I didn't find the configuration.

    My config:

    # app/config/security.yml
    
    security:
        encoders:
            FOS\UserBundle\Model\UserInterface: sha512
            Symfony\Component\Security\Core\User\User:
                algorithm: bcrypt
                cost: 12
    
        ...
    
        providers:
            fos_userbundle:
                id: fos_user.user_provider.username_email
            in_memory:
                memory:
                    users:
                        xxxx: { password: xxxx, roles: 'ROLE_ADMIN' }
    
        firewalls:
            # disables authentication for assets and the profiler, adapt it according to your needs
            dev:
                pattern:  ^/(_(profiler|wdt)|css|images|js)/
                security: false
    
            default:
                pattern: ^/api/doc
                provider: in_memory
                anonymous: ~
                http_basic:
                    realm: "xxxxx"
                    provider: in_memory
    
            authenticate:
                pattern:  ^/v1/authenticate
                stateless: true
                anonymous: true
                form_login:
                    check_path:               /v1/authenticate
                    success_handler:          lexik_jwt_authentication.handler.authentication_success
                    failure_handler:          lexik_jwt_authentication.handler.authentication_failure
                    require_previous_session: false
    
            refresh:
                pattern:  ^/v1/token/refresh
                stateless: true
                anonymous: true
    
            api:
                pattern:   ^/v1
                provider: fos_userbundle
                stateless: true
                anonymous: true
                lexik_jwt: ~
    
        access_control:
            - { path: ^/api/doc, roles: ROLE_ADMIN }
            - { path: ^v1/token/refresh, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    
    # app/config/routing.yml
    
    NelmioApiDocBundle:
        resource: "@NelmioApiDocBundle/Resources/config/routing.yml"
        prefix:   /api/doc
    
    fos_user:
        resource: "@FOSUserBundle/Resources/config/routing/all.xml"
    
    api_login_check:
        path: /v1/authenticate
    
    gesdinet_jwt_refresh_token:
        path:     /v1/token/refresh
        defaults: { _controller: gesdinet.jwtrefreshtoken:refresh }
    
    home:
        prefix:   /
        resource: AppBundle\Controller\HomeController
    ...
    
    opened by qdequippe 7
  • [1.x] Add forward compat layer for changed logout listener configuration

    [1.x] Add forward compat layer for changed logout listener configuration

    See https://github.com/markitosgv/JWTRefreshTokenBundle/pull/347/files/dd75327f8d93d178fa32cbaac929c90a84548ab0#r1037883273 for context

    The 2.0 proposal includes changing how the logout listener that handles token and cookie invalidation is configured. In the 2.0 branch, the listener is configured based on the authenticator configuration instead of the global bundle configuration, which allows improving multi-firewall compatibility by configuring the listener differently for each firewall. This provides a compatibility layer to start moving that config in a future 1.x release.

    Note that there are a couple of functional B/C breaks here:

    • The LogoutEventListener is turned into an abstract service definition that is used to configure concrete services, this impacts folks who might be using compiler passes in their own application to tweak this service
    • Changes the logout_firewall config node to default to null instead of "api", this is both a bug fix and a B/C break in that with the default config as it was previously you couldn't really turn off the listener without a compiler pass

    This also adds tests for the LogoutEventListener class, previously untested.

    opened by mbabker 1
  • [1.x] Fix PHP 8.2 compat issue in uses of `DateTime::modify()`

    [1.x] Fix PHP 8.2 compat issue in uses of `DateTime::modify()`

    As noted in https://github.com/php/php-src/issues/9950 there is a behavioral change in PHP 8.2 if you make a call like $dateTime->modify('+-300 seconds') as a result of another bug fix in the date/time handling libraries. As the bundle does not enforce TTLs to be a positive number (and the functional tests abuse this a bit), this is a practical fix to ensure anything passing a negative TTL value doesn't catastrophically break.

    opened by mbabker 1
  • 2.0 Proposal

    2.0 Proposal

    See #343 for details

    I'm leaving it as split-up commits to make it a little easier to see how everything evolved.

    If accepted as is, what I'd personally do is this:

    • Merge these PRs:
      • [ ] #328
      • [ ] #344
      • [x] #348
      • [ ] #349
      • [ ] #350
    • Cut a 1.2 release
    • Merge this
    • Cut a 2.0 beta
    opened by mbabker 0
  • 401 - Invalid Credentials

    401 - Invalid Credentials

    I have implemented this bundle but I'm getting a 401 - invalid credential error when I submit the refresh token. I log in and get a token as well as a refresh token at the same time. Directly after that I'm trying to POST with the refresh token to www.mywebsite.com/api/token/refresh.

    Here is my security.yaml file :

    `security: enable_authenticator_manager: true # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords password_hashers: Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto' App\Entity\User: algorithm: auto

    # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\User
                property: username
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        login:
            pattern: ^/api/login
            stateless: true
            json_login:
                check_path: /api/login
                username_path: username
                password_path: password
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure
        api:
            pattern: ^/api
            stateless: true
            entry_point: jwt
            jwt: ~
            refresh_jwt:
                check_path: /api/token/refresh
            logout:
                path: api_token_invalidate
        main:
            lazy: true
            provider: app_user_provider
    
            # activate different ways to authenticate
            # https://symfony.com/doc/current/security.html#the-firewall
    
            # https://symfony.com/doc/current/security/impersonating_user.html
            # switch_user: true
    
    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        - { path: ^/api/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY } # Allows accessing the Swagger UI
        #- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    

    - { path: ^/api/users, roles: IS_AUTHENTICATED_FULLY }

        # - { path: ^/admin, roles: ROLE_ADMIN }
        # - { path: ^/profile, roles: ROLE_USER }
        - { path: ^/api/login, roles: PUBLIC_ACCESS }
        #- { path: ^/api,       roles: IS_AUTHENTICATED_FULLY } @TODO à décommenter lors de la MEP
        - { path: ^/api/(login|token/refresh), roles: PUBLIC_ACCESS }
    

    when@test: security: password_hashers: # By default, password hashers are resource intensive and take time. This is # important to generate secure password hashes. In tests however, secure hashes # are not important, waste resources and increase test times. The following # reduces the work factor to the lowest possible values. Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: algorithm: auto cost: 4 # Lowest possible value for bcrypt time_cost: 3 # Lowest possible value for argon memory_cost: 10 # Lowest possible value for argon

    `

    Does anybody has an idea why I'm getting that response ?

    By the way the route to invalidate works perfectly.

    opened by PaxBryan 1
  • Compatibility bug with Symfony 6.1 & ApiPlatform 3.0

    Compatibility bug with Symfony 6.1 & ApiPlatform 3.0

    Hi everyone,

    I have problem with Symfony 6.1.0 and ApiPlatform 3.0.0

    After installing bundle via composer all my API routes disappeared (only LexikJWT route added by OpenAPI decorator left)

    image

    When I remove bundle from bundles.php all endpoints return

    image

    Here is my code:

    RefreshToken.php

    <?php
    
    declare(strict_types=1);
    
    namespace App\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    use Gesdinet\JWTRefreshTokenBundle\Entity\RefreshToken as BaseRefreshToken;
    
    #[ORM\Entity]
    #[ORM\Table('`refresh_tokens`')]
    class RefreshToken extends BaseRefreshToken
    {
    }
    
    

    security.yaml

    security:
        password_hashers:
            Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
        enable_authenticator_manager: true
        providers:
            app_user_provider:
                entity:
                    class: App\Entity\User
                    property: email
        firewalls:
            dev:
                pattern: ^/(_(profiler|wdt)|css|images|js)/
                security: false
    
            main:
                stateless: true
                provider: app_user_provider
                entry_point: jwt
                json_login:
                    check_path: /authentication_token
                    username_path: email
                    password_path: password
                    success_handler: lexik_jwt_authentication.handler.authentication_success
                    failure_handler: lexik_jwt_authentication.handler.authentication_failure
                jwt: ~
                refresh_jwt:
                    check_path: /token/refresh
                    provider: app_user_provider
    
        access_control:
            - { path: ^/authentication_token, roles: PUBLIC_ACCESS }
            - { path: ^/token/refresh, roles: PUBLIC_ACCESS }
            - { path: ^/api$, roles: PUBLIC_ACCESS }
    #        - { path: ^/, roles: IS_AUTHENTICATED_FULLY }
    

    Anyone have any solution?

    opened by ppoz21 6
Releases(v1.1.1)
  • v1.1.0(Apr 11, 2022)

  • v1.0.0(Jan 15, 2022)

    Stable release with Symfony 6 support

    What's Changed

    • CI updates and bump minimum supported versions by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/245
    • Switch to GitHub Actions by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/249
    • Refactor the data model, Doctrine, and validation structures by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/247
    • New authenticator for the newer Symfony authenticator API by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/246
    • Fix deprecation versions by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/250
    • Use PHPUnit for command and DI tests by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/252
    • Added specialized exceptions by @Igorut in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/239
    • Restore accidentally removed Doctrine configs by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/254
    • Introduce a factory service for generating RefreshTokenInterface objects by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/251
    • Create a request extractor API to replace the static method for extracting the refresh token from the request by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/256
    • Bump minimum PHP to 7.4 by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/257
    • Test improvements by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/258
    • Add missing type docs and typehints by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/259
    • Require refresh token models to be Stringable by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/266
    • Add various fixes from PHPStan analysis by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/265
    • Add a gitattributes and optimize gitignore by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/264
    • Don't use deprecated base RefreshTokenManager class by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/263
    • Don't mark extractor services as public by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/262
    • Docs updates by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/268
    • Fix DI error by @Jayfrown in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/267
    • Repository interface by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/269
    • Update required PHP version in README by @marmichalski in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/272
    • Start testing on PHP 8.1 by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/278
    • Bump minimum PHPUnit version by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/276
    • Support setting refresh token in cookie by @Jayfrown in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/274
    • Apply fixes from StyleCI by @markitosgv in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/283
    • Updates based on Symfony 5.4 Security component deprecations by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/271
    • Move service deprecations into config file by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/277
    • Convert phpspec tests to phpunit tests by @webignition in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/293
    • Drop support for Symfony 3.4 and 5.3, add support for Symfony 6, drop MongoDB ODM 1.x by @mbabker in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/284
    • Apply fixes from StyleCI by @markitosgv in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/295

    New Contributors

    • @Igorut made their first contribution in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/239
    • @Jayfrown made their first contribution in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/267
    • @marmichalski made their first contribution in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/272
    • @webignition made their first contribution in https://github.com/markitosgv/JWTRefreshTokenBundle/pull/293

    Full Changelog: https://github.com/markitosgv/JWTRefreshTokenBundle/compare/v0.12.0...v1.0.0

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta4(Jul 29, 2021)

  • v1.0.0-beta3(Jul 19, 2021)

  • v1.0.0-beta2(Jul 12, 2021)

  • v1.0.0-beta(Jul 1, 2021)

  • v0.12.0(Apr 23, 2021)

  • v0.10.1(Jan 10, 2021)

  • v0.10.0(Dec 23, 2020)

  • v0.9.1(Feb 4, 2020)

  • v0.9.0(Dec 5, 2019)

  • v0.8.3(Nov 12, 2019)

  • v0.8.1(Oct 10, 2019)

  • v0.7.1(Jul 5, 2019)

  • v0.7.0(Jul 1, 2019)

  • v0.5.4(Dec 6, 2018)

  • v0.5.3(Sep 19, 2018)

  • v0.5.1(Sep 17, 2018)

  • v0.5.0(Sep 11, 2018)

  • v0.3.3(Mar 31, 2018)

Owner
Marcos Gómez Vilches
Marcos Gómez Vilches
🔐 JSON Web Token Authentication for Laravel & Lumen

Documentation Documentation for 1.* here For version 0.5.* See the WIKI for documentation. Supported by Auth0 If you want to easily add secure authent

Sean Tymon 10.7k Dec 31, 2022
Un proyecto que crea una API de usuarios para registro, login y luego acceder a su información mediante autenticación con JSON Web Token

JSON WEB TOKEN CON LARAVEL 8 Prueba de autenticación de usuarios con una API creada en Laravel 8 Simple, fast routing engine. License The Laravel fram

Yesser Miranda 2 Oct 10, 2021
🔐 JSON Web Token Authentication for Laravel & Lumen

Credits This repository it a fork from original tymonsdesigns/jwt-auth, we decided to fork and work independent because the original one was not being

null 490 Dec 27, 2022
JSON Web Token (JWT) for webman plugin

JSON Web Token (JWT) for webman plugin Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。

 ShaoBo Wan(無尘) 25 Dec 30, 2022
Learn Cookies and Tokens Security in Practice.

The full article is posted on my blog. The video presentation is shared here. The presentation slides are shared here. The exploit codes are shared he

HolyBugx 38 Aug 28, 2022
PASETO: Platform-Agnostic Security Tokens

PASETO: Platform-Agnostic Security Tokens Paseto is everything you love about JOSE (JWT, JWE, JWS) without any of the many design deficits that plague

Paragon Initiative Enterprises 3.1k Dec 27, 2022
Easily define tokens and options that can be replaced in strings.

Token Replace This simple package allows you to define tokens that can be replaced in strings. Instead of a simple str_replace, Token Replace lets you

Jamie Holly 2 Dec 21, 2022
Magic admin PHP SDK makes it easy to leverage Decentralized ID tokens to protect routes and restricted resources for your application.

Magic Admin PHP SDK The Magic Admin PHP SDK provides convenient ways for developers to interact with Magic API endpoints and an array of utilities to

magiclabs 17 Jun 26, 2022
Minimalistic token-based authorization for Laravel API endpoints.

Bearer Minimalistic token-based authorization for Laravel API endpoints. Installation You can install the package via Composer: composer require ryang

Ryan Chandler 74 Jun 17, 2022
Light-weight role-based permissions system for Laravel 6+ built in Auth system.

Kodeine/Laravel-ACL Laravel ACL adds role based permissions to built in Auth System of Laravel 8.0+. ACL middleware protects routes and even crud cont

Kodeine 781 Dec 15, 2022
Basic Authentication handler for the JSON API, used for development and debugging purposes

Basic Authentication handler This plugin adds Basic Authentication to a WordPress site. Note that this plugin requires sending your username and passw

WordPress REST API Team 667 Dec 31, 2022
OAuth client integration for Symfony. Supports both OAuth1.0a and OAuth2.

HWIOAuthBundle The HWIOAuthBundle adds support for authenticating users via OAuth1.0a or OAuth2 in Symfony. Note: this bundle adds easy way to impleme

Hardware Info 2.2k Dec 30, 2022
example of LexikJWTAuthenticationBundle with Symfony 4.4

Install Dependency composer install Generate the SSL keys: php bin/console lexik:jwt:generate-keypair Create database php bin/console doctrine:datab

Yunus Emre Bulut 1 Nov 10, 2021
Symfony bundle to publish status updates on Facebook, LinkedIn and Twitter.

Upgrading? Check the upgrade guide. What's this? This is a Symfony bundle written in PHP 7.1 that wraps martin-georgiev/social-post - an easy way for

Martin Georgiev 37 Oct 30, 2022
Symfony bundle which provides OAuth 2.0 authorization/resource server capabilities

Symfony bundle which provides OAuth 2.0 authorization/resource server capabilities. The authorization and resource server actors are implemented using the thephpleague/oauth2-server library.

Trikoder 253 Dec 21, 2022
JWT Authenticator for symfony

HalloVerdenJwtAuthenticatorBundle This bundle provides a JWT authenticator for Symfony applications. It's using PHP JWT Framework for parsing and vali

Hallo Verden 0 Jul 8, 2022
A framework agnostic authentication & authorization system.

Sentinel Sentinel is a PHP 7.3+ framework agnostic fully-featured authentication & authorization system. It also provides additional features such as

Cartalyst 1.4k Dec 30, 2022
UserFrosting is a secure, modern user management system written in PHP and built on top of the Slim Microframework, Twig templating engine, and Eloquent ORM.

UserFrosting is a secure, modern user management system written in PHP and built on top of the Slim Microframework, Twig templating engine, and Eloquent ORM.

UserFrosting 1.6k Jan 1, 2023
KeyAuth is an open source authentication system with cloud-hosted subscriptions available aswell

KeyAuth is an open source authentication system with cloud-hosted subscriptions available aswell

null 158 Dec 23, 2022