/**
  * Implements a generic OAuth service provider authentication
  *
  * @param  callable $callback A callable to call when OAuth authentication
  *                            starts
  * @param  string   $oauth    OAuth version to be used for authentication
  *
  * @return null|User          Returns a Grav user instance on success.
  */
 protected function genericOAuthProvider($callback, $oauth = 'oauth2')
 {
     /** @var Session */
     $session = $this->grav['session'];
     switch ($oauth) {
         case 'oauth1':
             if (empty($_GET['oauth_token']) && empty($_GET['oauth_verifier'])) {
                 // Extra request needed for OAuth1 to request a request token :-)
                 $token = $this->service->requestRequestToken();
                 // Create a state token to prevent request forgery.
                 // Store it in the session for later validation.
                 $redirect = $this->service->getAuthorizationUri(['oauth_token' => $token->getRequestToken()]);
                 $this->setRedirect($redirect);
                 // Update OAuth session
                 $session->oauth = $this->action;
             } else {
                 $token = $this->storage->retrieveAccessToken($session->oauth);
                 // This was a callback request from OAuth1 service, get the token
                 if (isset($_GET['_url'])) {
                     parse_str(parse_url($_GET['_url'])['query']);
                     $this->service->requestAccessToken($oauth_token, $_GET['oauth_verifier'], $token->getRequestTokenSecret());
                 } else {
                     $this->service->requestAccessToken($_GET['oauth_token'], $_GET['oauth_verifier'], $token->getRequestTokenSecret());
                 }
                 return $callback();
             }
             break;
         case 'oauth2':
         default:
             if (empty($_GET['code'])) {
                 // Create a state token to prevent request forgery (CSRF).
                 $state = sha1($this->getRandomBytes(1024, false));
                 $redirect = $this->service->getAuthorizationUri(['state' => $state]);
                 $this->setRedirect($redirect);
                 // Update OAuth session
                 $session->oauth = $this->action;
                 // Store CSRF in the session for later validation.
                 $this->storage->storeAuthorizationState($this->action, $state);
             } else {
                 // Retrieve the CSRF state parameter
                 $state = isset($_GET['state']) ? $_GET['state'] : null;
                 // This was a callback request from the OAuth2 service, get the token
                 $this->service->requestAccessToken($_GET['code'], $state);
                 return $callback();
             }
             break;
     }
     return;
 }