phpapisymfonyfosuserbundlefosoauthserverbundle

Generate Token on postPersist with FOSOAuthServerBundle


I'm trying to create a token on registration. I use FosUserBundle as authenticator and FOSOAuthServerBundle for API.

Everything works well when i generate a token manually. But i want to generate it automatically after a successful registration. So i created a EventListener called TokenSetter

Here is the code

class TokenSetter
{
protected $container;

public function __construct(ContainerInterface $container)
{
    $this->container = $container;
}

public function postPersist(LifecycleEventArgs $args)
{
    $user = $args->getEntity();

    if ($user instanceof Account) {
        $clientManager = $this->container->get('fos_oauth_server.client_manager.default');
        $client = $clientManager->createClient();
        $client->setRedirectUris(array('http://127.0.0.1:8000'));
        $client->setAllowedGrantTypes(array('password', 'refresh_token'));
        $clientManager->updateClient($client);

        $grantRequest = new Request(array(
            'client_id'  => $client->getPublicId(),
            'client_secret' => $client->getSecret(),
            'grant_type' => 'password',
            'username' => $user->getUsername(),
            'password' => $user->getPlainPassword()
        ));

        $tokenResponse = $this->container->get('fos_oauth_server.server')->grantAccessToken($grantRequest);

        $token = $tokenResponse->getContent();
    }
}
}

The issue is that the $user->getPlainPassword() returns a empty value. This results in a "invalid_request" after creation.

Is there a way to get the plain password or generate the token a different way?


Solution

  • Solved it myself.

    There are two ways to solve this.

    First method is to change password to client_credentials. This way you do not need to send a username and password when generating a access token. The down side is that the value of the user_id will be set to NULL.

    Second solution is to create a different listener. (RegistrationListener)

    You need to edit the UserEntity and add a TempPlainPass getter and setter. Basically what you need to do is, storing the plainpassword in the database onRegistrationSuccess and create a token with username and password on onRegistrationCompleted

    IMPORTANT! Don't forget to delete the TempPlainPass after generating a token

    See the code below:

    class RegistrationListener implements EventSubscriberInterface
    {
    protected $container;
    
    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }
    
    
    public static function getSubscribedEvents()
    {
        return array(
            FOSUserEvents::REGISTRATION_SUCCESS => 'onRegistrationSuccess',
            FOSUserEvents::REGISTRATION_COMPLETED => 'onRegistrationCompleted',
        );
    }
    
    public function onRegistrationSuccess(FormEvent $event)
    {
        $user = $event->getForm()->getData();
        $user->setTempPlainPass($user->getPlainPassword());
        $user->setRoles(array('ROLE_ADMIN'));
    }
    
    public function onRegistrationCompleted(FilterUserResponseEvent $event)
    {
        $user = $event->getUser();
        $clientManager = $this->container->get('fos_oauth_server.client_manager.default');
            $client = $clientManager->createClient();
            $client->setRedirectUris(array('http://127.0.0.1:8000'));
            $client->setAllowedGrantTypes(array('password', 'refresh_token'));
            $clientManager->updateClient($client);
    
            $grantRequest = new Request(array(
                'client_id'  => $client->getPublicId(),
                'client_secret' => $client->getSecret(),
                'grant_type' => 'password',
                'username' => $user->getUsername(),
                'password' => $user->getTempPlainPass()
            ));
    
            $this->container->get('fos_oauth_server.server')->grantAccessToken($grantRequest);
    
            $em = $this->container->get('doctrine.orm.default_entity_manager');
            $update = $em->getRepository(Account::class)->findOneById($user->getId());
            $update->setTempPlainPass('');
            $em->flush();
    }
    }