public function grant(array $data, array $headers = array(), array $query = array())
    {
        // create and validate login attempt from given data
        $loginAttempt = $this->createLoginAttempt(
            $data, $headers, $query
        );

        // load application / account
        $account = $this->loadAccount(
            $application = $this->loadApplication($loginAttempt),
            $loginAttempt
        );

        // event call
        $this->eventDispatcher->dispatch(
            AccessTokenEvents::MAJORA_ACCESS_TOKEN_CREATED,
            new AccessTokenEvent(

                // access token generation
                $accessToken = new $this->tokenOptions['access_token_class'](
                    $application,
                    $account,
                    $this->tokenOptions['access_token_ttl'],
                    null, // for now, we let the expiration date calculate itself
                    $this->randomTokenGenerator->generate('access_token'),

                    // refresh token generation only if necessary
                    in_array('refresh_token', $application->getAllowedGrantTypes())
                    && $this->grantExtensions->containsKey('refresh_token') ?
                        new $this->tokenOptions['refresh_token_class'](
                            $application,
                            $account,
                            $this->tokenOptions['refresh_token_ttl'],
                            null, // same
                            $this->randomTokenGenerator->generate('refresh_token')
                        ) :
                        null
                )
            )
        );

        return $accessToken;
    }