diff --git a/social_auth_vk.routing.yml b/social_auth_vk.routing.yml
index b0e32af..0d0f009 100644
--- a/social_auth_vk.routing.yml
+++ b/social_auth_vk.routing.yml
@@ -1,7 +1,7 @@
 social_auth_vk.redirect_to_vkontakte:
   path: 'user/login/vkontakte'
   defaults:
-    _controller: '\Drupal\social_auth_vk\Controller\VkontakteAuthController::redirectToVkontakte'
+    _controller: '\Drupal\social_auth_vk\Controller\VkontakteAuthController::redirectToProvider'
   requirements:
     # Anonymous users can log in, but authenticated users can also associate a new provider.
     _access: 'TRUE'
diff --git a/social_auth_vk.services.yml b/social_auth_vk.services.yml
index c4f2483..729dfa6 100644
--- a/social_auth_vk.services.yml
+++ b/social_auth_vk.services.yml
@@ -3,4 +3,5 @@ services:
     class: Drupal\social_auth_vk\VkontakteAuthManager
     arguments:
       - '@config.factory'
+      - '@logger.factory'
       - '@request_stack'
diff --git a/src/Controller/VkontakteAuthController.php b/src/Controller/VkontakteAuthController.php
index 963035d..4a29177 100644
--- a/src/Controller/VkontakteAuthController.php
+++ b/src/Controller/VkontakteAuthController.php
@@ -2,112 +2,44 @@
 
 namespace Drupal\social_auth_vk\Controller;
 
-use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\social_api\Plugin\NetworkManager;
-use Drupal\social_api\SocialApiException;
+use Drupal\social_auth\Controller\OAuth2ControllerBase;
 use Drupal\social_auth\SocialAuthDataHandler;
-use Drupal\social_auth\SocialAuthUserManager;
+use Drupal\social_auth\User\UserAuthenticator;
 use Drupal\social_auth_vk\VkontakteAuthManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Routing\TrustedRedirectResponse;
 use Symfony\Component\HttpFoundation\RequestStack;
-use Drupal\Core\Logger\LoggerChannelFactoryInterface;
 
 /**
- * Returns responses for Simple Vkontakte Connect module routes.
+ * Returns responses for Social Auth Vkontakte routes.
  */
-class VkontakteAuthController extends ControllerBase {
-
-  /**
-   * The network plugin manager.
-   *
-   * @var \Drupal\social_api\Plugin\NetworkManager
-   */
-  private $networkManager;
-
-  /**
-   * The user manager.
-   *
-   * @var \Drupal\social_auth\SocialAuthUserManager
-   */
-  private $userManager;
-
-  /**
-   * The vkontakte authentication manager.
-   *
-   * @var \Drupal\social_auth_vk\VkontakteAuthManager
-   */
-  private $vkontakteManager;
-
-  /**
-   * Used to access GET parameters.
-   *
-   * @var \Symfony\Component\HttpFoundation\RequestStack
-   */
-  private $request;
-
-  /**
-   * The Social Auth Data Handler.
-   *
-   * @var \Drupal\social_auth\SocialAuthDataHandler
-   */
-  private $dataHandler;
-
-
-  /**
-   * The logger channel.
-   *
-   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
-   */
-  protected $loggerFactory;
-
-  /**
-   * The Messenger service.
-   *
-   * @var \Drupal\Core\Messenger\MessengerInterface
-   */
-  protected $messenger;
-
-  /**
-   * Logger channel name.
-   *
-   * @var string
-   */
-  protected $loggerChannel = 'Social Auth Vkontakte';
+class VkontakteAuthController extends OAuth2ControllerBase {
 
   /**
    * VkontakteAuthController constructor.
    *
+   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
+   *   The messenger service.
    * @param \Drupal\social_api\Plugin\NetworkManager $network_manager
    *   Used to get an instance of social_auth_vk network plugin.
-   * @param \Drupal\social_auth\SocialAuthUserManager $user_manager
-   *   Manages user login/registration.
-   * @param \Drupal\social_auth_vk\VkontakteAuthManager $vkontakte_manager
+   * @param \Drupal\social_auth\User\UserAuthenticator $user_authenticator
+   *   Used to manage user authentication/registration.
+   * @param \Drupal\social_auth_vk\VkontakteAuthManager $vk_manager
    *   Used to manage authentication methods.
    * @param \Symfony\Component\HttpFoundation\RequestStack $request
    *   Used to access GET parameters.
-   * @param \Drupal\social_auth\SocialAuthDataHandler $social_auth_data_handler
-   *   SocialAuthDataHandler object.
-   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
-   *   Used for logging errors.
-   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
-   *   The messenger service.
+   * @param \Drupal\social_auth\SocialAuthDataHandler $data_handler
+   *   The Social Auth data handler.
    */
-  public function __construct(NetworkManager $network_manager, SocialAuthUserManager $user_manager, VkontakteAuthManager $vkontakte_manager, RequestStack $request, SocialAuthDataHandler $social_auth_data_handler, LoggerChannelFactoryInterface $logger_factory, MessengerInterface $messenger) {
-    $this->networkManager = $network_manager;
-    $this->userManager = $user_manager;
-    $this->vkontakteManager = $vkontakte_manager;
-    $this->request = $request;
-    $this->dataHandler = $social_auth_data_handler;
-    $this->loggerFactory = $logger_factory;
-    $this->messenger = $messenger;
-
-    // Sets the plugin id.
-    $this->userManager->setPluginId('social_auth_vk');
-
-    // Sets the session keys to nullify if user could not logged in.
-    $this->userManager->setSessionKeysToNullify(['access_token', 'oauth2state']);
+  public function __construct(MessengerInterface $messenger,
+                              NetworkManager $network_manager,
+                              UserAuthenticator $user_authenticator,
+                              VkontakteAuthManager $vk_manager,
+                              RequestStack $request,
+                              SocialAuthDataHandler $data_handler) {
+
+    parent::__construct('Social Auth Vkontakte', 'social_auth_vk', $messenger, $network_manager, $user_authenticator, $vk_manager, $request, $data_handler);
   }
 
   /**
@@ -115,113 +47,39 @@ class VkontakteAuthController extends ControllerBase {
    */
   public static function create(ContainerInterface $container) {
     return new static(
+      $container->get('messenger'),
       $container->get('plugin.network.manager'),
-      $container->get('social_auth.user_manager'),
+      $container->get('social_auth.user_authenticator'),
       $container->get('social_auth_vk.manager'),
       $container->get('request_stack'),
-      $container->get('social_auth.data_handler'),
-      $container->get('logger.factory'),
-      $container->get('messenger')
+      $container->get('social_auth.data_handler')
     );
   }
 
-  /**
-   * Gets the underlying SDK library.
-   *
-   * @return \VK\OAuth\VKOAuth
-   *   The VKOAuth client.
-   *
-   * @throws \Drupal\Component\Plugin\Exception\PluginException
-   *   Thrown when no more class is applicable.
-   */
-  protected function getSdk() {
-    /** @var \Drupal\social_auth_vk\Plugin\Network\VkontakteAuth $plugin */
-    return $this->networkManager->createInstance('social_auth_vk')->getSdk();
-  }
-
-  /**
-   * Response for path 'user/login/vkontakte'.
-   *
-   * Redirects the user to Vkontakte for authentication.
-   *
-   * @return \Symfony\Component\HttpFoundation\RedirectResponse
-   *   Redirect response.
-   */
-  public function redirectToVkontakte() {
-    try {
-      $vkontakte = $this->getSdk();
-
-      // Vkontakte service was returned, inject it to $vkontakteManager.
-      $this->vkontakteManager->setOAuth($vkontakte);
-
-      // Generates the URL where the user will be redirected
-      // for Vkontakte login.
-      $vkontakte_login_url = $this->vkontakteManager->getAuthorizationUrl();
-
-      $state = $this->vkontakteManager->getState();
-
-      $this->dataHandler->set('oauth2state', $state);
-
-      $response = new TrustedRedirectResponse($vkontakte_login_url);
-    }
-    catch (\Exception $exception) {
-      $this->messenger->addError($this->t('Social Auth Vkontakte not configured properly. Contact site administrator.'));
-      $this->loggerFactory->get($this->loggerChannel)->error($exception->getMessage());
-      $response = $this->redirect('user.login');
-    }
-
-    return $response;
-  }
-
   /**
    * Response for path 'user/login/vkontakte/callback'.
    *
-   * Vkontakte returns the user here after user has authenticated in Vkontakte.
-   *
-   * @return \Symfony\Component\HttpFoundation\RedirectResponse
-   *   Redirect response.
+   * Vkontakte returns the user here after user has authenticated.
    */
   public function callback() {
-    try {
-      // Checks if user cancel login via Vkontakte.
-      $error = $this->request->getCurrentRequest()->get('error');
-      if ($error === 'access_denied') {
-        throw new SocialApiException('You could not be authenticated.');
-      }
+    // Checks if authentication failed.
+    if ($this->request->getCurrentRequest()->query->has('error')) {
+      $this->messenger->addError($this->t('You could not be authenticated.'));
 
-      // Retreives $_GET['state'].
-      $state = $this->dataHandler->get('oauth2state');
-      $retrievedState = $this->request->getCurrentRequest()->query->get('state');
-      if (empty($retrievedState) || ($retrievedState !== $state)) {
-        $this->userManager->nullifySessionKeys();
-        throw new SocialApiException('Vkontakte login failed. Invalid OAuth2 State.');
-      }
-
-      $vkontakte = $this->getSdk();
-      $this->vkontakteManager->setOAuth($vkontakte)->authenticate();
+      return $this->redirect('user.login');
+    }
 
-      // Saves access token to session.
-      $this->dataHandler->set('access_token', $this->vkontakteManager->getAccessToken());
+    /* @var array|null $profile */
+    $profile = $this->processCallback();
 
-      // Gets user's info from Vkontakte API.
-      $profile = $this->vkontakteManager->getUserInfo();
+    // If authentication was successful.
+    if ($profile !== NULL) {
       $full_name = $profile['first_name'] . ' ' . $profile['last_name'];
 
-      // Gets (or not) extra initial data.
-      $data = !$this->userManager->checkIfUserExists($profile['id'])
-        ? $this->vkontakteManager->getExtraDetails()
-        : [];
-
-      // If user information could be retrieved.
-      $response = $this->userManager->authenticateUser($full_name, $profile['email'], $profile['id'], $this->vkontakteManager->getAccessToken(), $profile['photo_max_orig'], $data);
-    }
-    catch (\Exception $exception) {
-      $this->messenger->addError($this->t('Social Auth Vkontakte not configured properly. Contact site administrator.'));
-      $this->loggerFactory->get($this->loggerChannel)->error($exception->getMessage());
-      $response = $this->redirect('user.login');
+      return $this->userAuthenticator->authenticateUser($full_name, $profile['email'], $profile['id'], $this->providerManager->getAccessToken(), $profile['photo_max_orig'], NULL);
     }
 
-    return $response;
+    return $this->redirect('user.login');
   }
 
 }
diff --git a/src/Plugin/Network/VkontakteAuth.php b/src/Plugin/Network/VkontakteAuth.php
index b213a85..b94b47f 100644
--- a/src/Plugin/Network/VkontakteAuth.php
+++ b/src/Plugin/Network/VkontakteAuth.php
@@ -12,7 +12,7 @@ use Drupal\social_api\SocialApiException;
 use Drupal\social_auth_vk\Settings\VkontakteAuthSettings;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Site\Settings;
-use VK\OAuth\VKOAuth;
+use VK\Client\VKApiClient;
 
 /**
  * Defines a Network Plugin for Social Auth Vkontakte.
@@ -115,8 +115,7 @@ class VkontakteAuth extends NetworkBase implements VkontakteAuthInterface {
                               ConfigFactoryInterface $config_factory,
                               LoggerChannelFactoryInterface $logger_factory,
                               RequestContext $requestContext,
-                              Settings $settings
-  ) {
+                              Settings $settings) {
 
     parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $config_factory);
 
@@ -129,14 +128,14 @@ class VkontakteAuth extends NetworkBase implements VkontakteAuthInterface {
   /**
    * Sets the underlying SDK library.
    *
-   * @return \VK\OAuth\VKOAuth
+   * @return \VK\Client\VKApiClient
    *   The initialized 3rd party library instance.
    *
    * @throws SocialApiException
    *   If the SDK library does not exist.
    */
   protected function initSdk() {
-    $class_name = VKOAuth::class;
+    $class_name = VKApiClient::class;
     if (!class_exists($class_name)) {
       throw new SocialApiException(sprintf('The Vkontakte Library not found. Class: %s.', $class_name));
     }
@@ -145,7 +144,7 @@ class VkontakteAuth extends NetworkBase implements VkontakteAuthInterface {
       throw new SocialApiException('Social Auth Vkontakte not configured properly. Contact site administrator.');
     }
 
-    return new VKOAuth();
+    return new VKApiClient();
   }
 
   /**
diff --git a/src/VkontakteAuthManager.php b/src/VkontakteAuthManager.php
index 619e119..7d93ca4 100644
--- a/src/VkontakteAuthManager.php
+++ b/src/VkontakteAuthManager.php
@@ -2,8 +2,9 @@
 
 namespace Drupal\social_auth_vk;
 
-use Drupal\Core\Url;
 use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Logger\LoggerChannelFactoryInterface;
+use Drupal\Core\Url;
 use Drupal\social_api\SocialApiException;
 use Drupal\social_auth\AuthManager\OAuth2Manager;
 use Symfony\Component\HttpFoundation\RequestStack;
@@ -11,10 +12,9 @@ use VK\OAuth\VKOAuth;
 use VK\OAuth\VKOAuthDisplay;
 use VK\OAuth\Scopes\VKOAuthUserScope;
 use VK\OAuth\VKOAuthResponseType;
-use VK\Client\VKApiClient;
 
 /**
- * Contains all the logic for Vkontakte login integration.
+ * Contains all the logic for Vkontakte OAuth2 authentication.
  */
 class VkontakteAuthManager extends OAuth2Manager {
 
@@ -40,7 +40,7 @@ class VkontakteAuthManager extends OAuth2Manager {
   protected $client;
 
   /**
-   * The OAuth client.
+   * The VkOAuth object used for authorization.
    *
    * @var \VK\OAuth\VKOAuth
    */
@@ -53,32 +53,106 @@ class VkontakteAuthManager extends OAuth2Manager {
    */
   protected $request;
 
+  /**
+   * The secret state for the authentication.
+   *
+   * @var string
+   */
+  protected $state;
+
   /**
    * Constructor.
    *
    * @param \Drupal\Core\Config\ConfigFactory $configFactory
    *   Used for accessing configuration object factory.
+   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
+   *   The logger factory.
+   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
+   *   Used to get current request information.
    */
-  public function __construct(ConfigFactory $configFactory, RequestStack $request_stack) {
-    parent::__construct($configFactory->get('social_auth_vk.settings'));
+  public function __construct(ConfigFactory $configFactory,
+                              LoggerChannelFactoryInterface $logger_factory,
+                              RequestStack $request_stack) {
+    parent::__construct($configFactory->get('social_auth_vk.settings'), $logger_factory);
 
-    $this->client = new VKApiClient();
+    $this->oauth = new VKOAuth();
     $this->request = $request_stack->getCurrentRequest();
   }
 
   /**
-   * Set OAuth to authorization and authentication.
-   *
-   * @param \VK\OAuth\VKOAuth $oauth
-   *   VKOAuth object.
-   *
-   * @return \Drupal\social_auth_vk\VkontakteAuthManager
-   *   The current object.
+   * {@inheritdoc}
    */
-  public function setOAuth(VKOAuth $oauth) {
-    $this->oauth = $oauth;
+  public function authenticate() {
+    $client_id = $this->getClientId();
+    $client_secret = $this->getClientSecret();
+    $redirect_uri = $this->getRedirectUrl();
+    $code = $this->request->query->get('code');
 
-    return $this;
+    try {
+      $response = $this->oauth->getAccessToken($client_id, $client_secret, $redirect_uri, $code);
+
+      if ($response) {
+        if (isset($response['access_token'])) {
+          $this->setAccessToken($response['access_token']);
+        }
+
+        if (isset($response['email'])) {
+          $this->setEmail($response['email']);
+        }
+
+        if (isset($response['user_id'])) {
+          $this->setUserId($response['user_id']);
+        }
+      }
+    }
+    catch (\Exception $e) {
+      $this->loggerFactory->get('social_auth_vk')
+        ->error('There was an error during authentication. Exception: ' . $e->getMessage());
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getUserInfo() {
+
+    if (!$this->user) {
+      $user_ids = [$this->getUserId()];
+      $fields = ['id', 'first_name', 'last_name', 'photo_max_orig'];
+
+      $profile = $this->getProfileData($user_ids, $fields);
+      $profile['email'] = $this->getEmail();
+
+      $this->user = $profile;
+    }
+
+    return $this->user;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAuthorizationUrl() {
+    $client_id = $this->getClientId();
+    $redirect_uri = $this->getRedirectUrl();
+    $state = $this->getState();
+    $display = VKOAuthDisplay::PAGE;
+
+    $scopes = [VKOAuthUserScope::EMAIL, VKOAuthUserScope::OFFLINE];
+
+    $extra_scopes = $this->getScopes();
+    if ($extra_scopes) {
+      $scopes = array_merge($scopes, explode(',', $extra_scopes));
+    }
+
+    return $this->oauth->getAuthorizeUrl(VKOAuthResponseType::CODE, $client_id, $redirect_uri, $display, $scopes, $state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function requestEndPoint($method, $path, $domain = NULL) {
+    // TODO: Implement this method.
   }
 
   /**
@@ -132,80 +206,24 @@ class VkontakteAuthManager extends OAuth2Manager {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function authenticate() {
-    $client_id = $this->getClientId();
-    $client_secret = $this->getClientSecret();
-    $redirect_uri = $this->getRedirectUrl();
-    $code = $this->request->query->get('code');
-
-    $response = $this->oauth->getAccessToken($client_id, $client_secret, $redirect_uri, $code);
-    if ($response) {
-      if (isset($response['access_token'])) {
-        $this->setAccessToken($response['access_token']);
-      }
-
-      if (isset($response['email'])) {
-        $this->setEmail($response['email']);
-      }
-
-      if (isset($response['user_id'])) {
-        $this->setUserId($response['user_id']);
-      }
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getUserInfo() {
-    $user_ids = [$this->getUserId()];
-    $fields = ['id', 'first_name', 'last_name', 'photo_max_orig'];
-
-    $profiles = $this->loadProfilesData($user_ids, $fields);
-    $profile = reset($profiles);
-    $profile['email'] = $this->getEmail();
-
-    return $profile;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getAuthorizationUrl() {
-    $client_id = $this->getClientId();
-    $redirect_uri = $this->getRedirectUrl();
-    $state = $this->getState();
-    $display = VKOAuthDisplay::PAGE;
-
-    $scopes = [VKOAuthUserScope::EMAIL, VKOAuthUserScope::OFFLINE];
-    if ($extra_scopes = $this->getScopes()){
-      $scopes = array_merge($scopes, explode(',', $extra_scopes));
-    }
-
-    return $this->oauth->getAuthorizeUrl(VKOAuthResponseType::CODE, $client_id, $redirect_uri, $display, $scopes, $state);
-  }
-
-  /**
-   * Load profiles data.
+   * Get profile's data.
    *
    * @param array $user_ids
-   *   User ids.
+   *   The user ids.
    * @param array $fields
-   *   Fields list to load.
+   *   The fields to load.
    *
    * @return array
-   *   Profiles list.
+   *   The user profile.
    *
    * @throws \Drupal\social_api\SocialApiException
-   *   If profiles list is empty.
+   *   If profile list is empty.
    * @throws \VK\Exceptions\VKApiException
    *   Wrong request data.
    * @throws \VK\Exceptions\VKClientException
    *   Request errors.
    */
-  protected function loadProfilesData($user_ids, $fields) {
+  protected function getProfileData(array $user_ids, array $fields) {
     $profiles = $this->client->users()->get($this->getAccessToken(), [
       'fields' => $fields,
       'user_ids' => $user_ids,
@@ -215,34 +233,22 @@ class VkontakteAuthManager extends OAuth2Manager {
       throw new SocialApiException('Vkontakte login failed, could not load Vkontakte profile.');
     }
 
-    return $profiles;
+    return $profiles[0];
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getExtraDetails() {
-    $user_ids = [$this->getUserId()];
-    $fields = [
-      'verified', 'sex', 'bdate', 'city', 'country', 'home_town', 'education',
-      'universities', 'schools',
-    ];
-
-    $profiles = $this->loadProfilesData($user_ids, $fields);
-
-    return reset($profiles);
-  }
+  public function getState() {
+    if (!$this->state) {
+      $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+      $length = 32;
 
-  /**
-   * {@inheritdoc}
-   */
-  public function requestEndPoint($path) {}
+      // Generates a random string of 32 characters.
+      $this->state = substr(str_shuffle(str_repeat($chars, ceil($length / strlen($chars)))), 1, $length);
+    }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getState() {
-    return 'secret_state_code';
+    return $this->state;
   }
 
   /**
@@ -269,13 +275,10 @@ class VkontakteAuthManager extends OAuth2Manager {
    * Get redirect url.
    *
    * @return string
-   *   Redirect url.
+   *   The redirect url.
    */
   public function getRedirectUrl() {
-    $callback_uri = Url::fromRoute('social_auth_vk.callback');
-    $callback_uri->setAbsolute();
-
-    return $callback_uri->toString(TRUE)->getGeneratedUrl();
+    return Url::fromRoute('social_auth_vk.callback')->setAbsolute()->toString();
   }
 
 }
