Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
/lib/ -> oauthlib.php (source)

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  
  18  defined('MOODLE_INTERNAL') || die();
  19  
  20  require_once($CFG->libdir.'/filelib.php');
  21  
  22  /**
  23   * OAuth helper class
  24   *
  25   * 1. You can extends oauth_helper to add specific functions, such as twitter extends oauth_helper
  26   * 2. Call request_token method to get oauth_token and oauth_token_secret, and redirect user to authorize_url,
  27   *    developer needs to store oauth_token and oauth_token_secret somewhere, we will use them to request
  28   *    access token later on
  29   * 3. User approved the request, and get back to moodle
  30   * 4. Call get_access_token, it takes previous oauth_token and oauth_token_secret as arguments, oauth_token
  31   *    will be used in OAuth request, oauth_token_secret will be used to bulid signature, this method will
  32   *    return access_token and access_secret, store these two values in database or session
  33   * 5. Now you can access oauth protected resources by access_token and access_secret using oauth_helper::request
  34   *    method (or get() post())
  35   *
  36   * Note:
  37   * 1. This class only support HMAC-SHA1
  38   * 2. oauth_helper class don't store tokens and secrets, you must store them manually
  39   * 3. Some functions are based on http://code.google.com/p/oauth/
  40   *
  41   * @package    moodlecore
  42   * @copyright  2010 Dongsheng Cai <dongsheng@moodle.com>
  43   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  44   */
  45  
  46  class oauth_helper {
  47      /** @var string consumer key, issued by oauth provider*/
  48      protected $consumer_key;
  49      /** @var string consumer secret, issued by oauth provider*/
  50      protected $consumer_secret;
  51      /** @var string oauth root*/
  52      protected $api_root;
  53      /** @var string request token url*/
  54      protected $request_token_api;
  55      /** @var string authorize url*/
  56      protected $authorize_url;
  57      protected $http_method;
  58      /** @var string */
  59      protected $access_token_api;
  60      /** @var curl */
  61      protected $http;
  62      /** @var array options to pass to the next curl request */
  63      protected $http_options;
  64  
  65      /**
  66       * Contructor for oauth_helper.
  67       * Subclass can override construct to build its own $this->http
  68       *
  69       * @param array $args requires at least three keys, oauth_consumer_key
  70       *                    oauth_consumer_secret and api_root, oauth_helper will
  71       *                    guess request_token_api, authrize_url and access_token_api
  72       *                    based on api_root, but it not always works
  73       */
  74      function __construct($args) {
  75          if (!empty($args['api_root'])) {
  76              $this->api_root = $args['api_root'];
  77          } else {
  78              $this->api_root = '';
  79          }
  80          $this->consumer_key = $args['oauth_consumer_key'];
  81          $this->consumer_secret = $args['oauth_consumer_secret'];
  82  
  83          if (empty($args['request_token_api'])) {
  84              $this->request_token_api = $this->api_root . '/request_token';
  85          } else {
  86              $this->request_token_api = $args['request_token_api'];
  87          }
  88  
  89          if (empty($args['authorize_url'])) {
  90              $this->authorize_url = $this->api_root . '/authorize';
  91          } else {
  92              $this->authorize_url = $args['authorize_url'];
  93          }
  94  
  95          if (empty($args['access_token_api'])) {
  96              $this->access_token_api = $this->api_root . '/access_token';
  97          } else {
  98              $this->access_token_api = $args['access_token_api'];
  99          }
 100  
 101          if (!empty($args['oauth_callback'])) {
 102              $this->oauth_callback = new moodle_url($args['oauth_callback']);
 103          }
 104          if (!empty($args['access_token'])) {
 105              $this->access_token = $args['access_token'];
 106          }
 107          if (!empty($args['access_token_secret'])) {
 108              $this->access_token_secret = $args['access_token_secret'];
 109          }
 110          $this->http = new curl(array('debug'=>false));
 111          if (!empty($args['http_options'])) {
 112              $this->http_options = $args['http_options'];
 113          } else {
 114              $this->http_options = array();
 115          }
 116      }
 117  
 118      /**
 119       * Build parameters list:
 120       *    oauth_consumer_key="0685bd9184jfhq22",
 121       *    oauth_nonce="4572616e48616d6d65724c61686176",
 122       *    oauth_token="ad180jjd733klru7",
 123       *    oauth_signature_method="HMAC-SHA1",
 124       *    oauth_signature="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D",
 125       *    oauth_timestamp="137131200",
 126       *    oauth_version="1.0"
 127       *    oauth_verifier="1.0"
 128       * @param array $param
 129       * @return string
 130       */
 131      function get_signable_parameters($params){
 132          $sorted = $params;
 133          ksort($sorted);
 134  
 135          $total = array();
 136          foreach ($sorted as $k => $v) {
 137              if ($k == 'oauth_signature') {
 138                  continue;
 139              }
 140  
 141              $total[] = rawurlencode($k) . '=' . rawurlencode($v);
 142          }
 143          return implode('&', $total);
 144      }
 145  
 146      /**
 147       * Create signature for oauth request
 148       * @param string $url
 149       * @param string $secret
 150       * @param array $params
 151       * @return string
 152       */
 153      public function sign($http_method, $url, $params, $secret) {
 154          $sig = array(
 155              strtoupper($http_method),
 156              preg_replace('/%7E/', '~', rawurlencode($url)),
 157              rawurlencode($this->get_signable_parameters($params)),
 158          );
 159  
 160          $base_string = implode('&', $sig);
 161          $sig = base64_encode(hash_hmac('sha1', $base_string, $secret, true));
 162          return $sig;
 163      }
 164  
 165      /**
 166       * Initilize oauth request parameters, including:
 167       *    oauth_consumer_key="0685bd9184jfhq22",
 168       *    oauth_token="ad180jjd733klru7",
 169       *    oauth_signature_method="HMAC-SHA1",
 170       *    oauth_signature="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D",
 171       *    oauth_timestamp="137131200",
 172       *    oauth_nonce="4572616e48616d6d65724c61686176",
 173       *    oauth_version="1.0"
 174       * To access protected resources, oauth_token should be defined
 175       *
 176       * @param string $url
 177       * @param string $token
 178       * @param string $http_method
 179       * @return array
 180       */
 181      public function prepare_oauth_parameters($url, $params, $http_method = 'POST') {
 182          if (is_array($params)) {
 183              $oauth_params = $params;
 184          } else {
 185              $oauth_params = array();
 186          }
 187          $oauth_params['oauth_version']	     = '1.0';
 188          $oauth_params['oauth_nonce']	     = $this->get_nonce();
 189          $oauth_params['oauth_timestamp']    = $this->get_timestamp();
 190          $oauth_params['oauth_consumer_key'] = $this->consumer_key;
 191          $oauth_params['oauth_signature_method']	 = 'HMAC-SHA1';
 192          $oauth_params['oauth_signature']	 = $this->sign($http_method, $url, $oauth_params, $this->sign_secret);
 193          return $oauth_params;
 194      }
 195  
 196      public function setup_oauth_http_header($params) {
 197  
 198          $total = array();
 199          ksort($params);
 200          foreach ($params as $k => $v) {
 201              $total[] = rawurlencode($k) . '="' . rawurlencode($v).'"';
 202          }
 203          $str = implode(', ', $total);
 204          $str = 'Authorization: OAuth '.$str;
 205          $this->http->setHeader('Expect:');
 206          $this->http->setHeader($str);
 207      }
 208  
 209      /**
 210       * Sets the options for the next curl request
 211       *
 212       * @param array $options
 213       */
 214      public function setup_oauth_http_options($options) {
 215          $this->http_options = $options;
 216      }
 217  
 218      /**
 219       * Request token for authentication
 220       * This is the first step to use OAuth, it will return oauth_token and oauth_token_secret
 221       * @return array
 222       */
 223      public function request_token() {
 224          $this->sign_secret = $this->consumer_secret.'&';
 225  
 226          if (empty($this->oauth_callback)) {
 227              $params = [];
 228          } else {
 229              $params = ['oauth_callback' => $this->oauth_callback->out(false)];
 230          }
 231  
 232          $params = $this->prepare_oauth_parameters($this->request_token_api, $params, 'GET');
 233          $content = $this->http->get($this->request_token_api, $params, $this->http_options);
 234          // Including:
 235          //     oauth_token
 236          //     oauth_token_secret
 237          $result = $this->parse_result($content);
 238          if (empty($result['oauth_token'])) {
 239              throw new moodle_exception('oauth1requesttoken', 'core_error', '', null, $content);
 240          }
 241          // Build oauth authorize url.
 242          $result['authorize_url'] = $this->authorize_url . '?oauth_token='.$result['oauth_token'];
 243  
 244          return $result;
 245      }
 246  
 247      /**
 248       * Set oauth access token for oauth request
 249       * @param string $token
 250       * @param string $secret
 251       */
 252      public function set_access_token($token, $secret) {
 253          $this->access_token = $token;
 254          $this->access_token_secret = $secret;
 255      }
 256  
 257      /**
 258       * Request oauth access token from server
 259       * @param string $method
 260       * @param string $url
 261       * @param string $token
 262       * @param string $secret
 263       */
 264      public function get_access_token($token, $secret, $verifier='') {
 265          $this->sign_secret = $this->consumer_secret.'&'.$secret;
 266          $params = $this->prepare_oauth_parameters($this->access_token_api, array('oauth_token'=>$token, 'oauth_verifier'=>$verifier), 'POST');
 267          $this->setup_oauth_http_header($params);
 268          // Should never send the callback in this request.
 269          unset($params['oauth_callback']);
 270          $content = $this->http->post($this->access_token_api, $params, $this->http_options);
 271          $keys = $this->parse_result($content);
 272  
 273          if (empty($keys['oauth_token']) || empty($keys['oauth_token_secret'])) {
 274              throw new moodle_exception('oauth1accesstoken', 'core_error', '', null, $content);
 275          }
 276  
 277          $this->set_access_token($keys['oauth_token'], $keys['oauth_token_secret']);
 278          return $keys;
 279      }
 280  
 281      /**
 282       * Request oauth protected resources
 283       * @param string $method
 284       * @param string $url
 285       * @param string $token
 286       * @param string $secret
 287       */
 288      public function request($method, $url, $params=array(), $token='', $secret='') {
 289          if (empty($token)) {
 290              $token = $this->access_token;
 291          }
 292          if (empty($secret)) {
 293              $secret = $this->access_token_secret;
 294          }
 295          // to access protected resource, sign_secret will alwasy be consumer_secret+token_secret
 296          $this->sign_secret = $this->consumer_secret.'&'.$secret;
 297          if (strtolower($method) === 'post' && !empty($params)) {
 298              $oauth_params = $this->prepare_oauth_parameters($url, array('oauth_token'=>$token) + $params, $method);
 299          } else {
 300              $oauth_params = $this->prepare_oauth_parameters($url, array('oauth_token'=>$token), $method);
 301          }
 302          $this->setup_oauth_http_header($oauth_params);
 303          $content = call_user_func_array(array($this->http, strtolower($method)), array($url, $params, $this->http_options));
 304          // reset http header and options to prepare for the next request
 305          $this->http->resetHeader();
 306          // return request return value
 307          return $content;
 308      }
 309  
 310      /**
 311       * shortcut to start http get request
 312       */
 313      public function get($url, $params=array(), $token='', $secret='') {
 314          return $this->request('GET', $url, $params, $token, $secret);
 315      }
 316  
 317      /**
 318       * shortcut to start http post request
 319       */
 320      public function post($url, $params=array(), $token='', $secret='') {
 321          return $this->request('POST', $url, $params, $token, $secret);
 322      }
 323  
 324      /**
 325       * A method to parse oauth response to get oauth_token and oauth_token_secret
 326       * @param string $str
 327       * @return array
 328       */
 329      public function parse_result($str) {
 330          if (empty($str)) {
 331              throw new moodle_exception('error');
 332          }
 333          $parts = explode('&', $str);
 334          $result = array();
 335          foreach ($parts as $part){
 336              list($k, $v) = explode('=', $part, 2);
 337              $result[urldecode($k)] = urldecode($v);
 338          }
 339          if (empty($result)) {
 340              throw new moodle_exception('error');
 341          }
 342          return $result;
 343      }
 344  
 345      /**
 346       * Set nonce
 347       */
 348      function set_nonce($str) {
 349          $this->nonce = $str;
 350      }
 351      /**
 352       * Set timestamp
 353       */
 354      function set_timestamp($time) {
 355          $this->timestamp = $time;
 356      }
 357      /**
 358       * Generate timestamp
 359       */
 360      function get_timestamp() {
 361          if (!empty($this->timestamp)) {
 362              $timestamp = $this->timestamp;
 363              unset($this->timestamp);
 364              return $timestamp;
 365          }
 366          return time();
 367      }
 368      /**
 369       * Generate nonce for oauth request
 370       */
 371      function get_nonce() {
 372          if (!empty($this->nonce)) {
 373              $nonce = $this->nonce;
 374              unset($this->nonce);
 375              return $nonce;
 376          }
 377          $mt = microtime();
 378          $rand = mt_rand();
 379  
 380          return md5($mt . $rand);
 381      }
 382  }
 383  
 384  /**
 385   * OAuth 2.0 Client for using web access tokens.
 386   *
 387   * http://tools.ietf.org/html/draft-ietf-oauth-v2-22
 388   *
 389   * @package   core
 390   * @copyright Dan Poltawski <talktodan@gmail.com>
 391   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 392   */
 393  abstract class oauth2_client extends curl {
 394      /** @var string $clientid client identifier issued to the client */
 395      private $clientid = '';
 396      /** @var string $clientsecret The client secret. */
 397      private $clientsecret = '';
 398      /** @var moodle_url $returnurl URL to return to after authenticating */
 399      private $returnurl = null;
 400      /** @var string $scope of the authentication request */
 401      protected $scope = '';
 402      /** @var stdClass $accesstoken access token object */
 403      protected $accesstoken = null;
 404      /** @var string $refreshtoken refresh token string */
 405      protected $refreshtoken = '';
 406      /** @var string $mocknextresponse string */
 407      private $mocknextresponse = '';
 408      /** @var array $upgradedcodes list of upgraded codes in this request */
 409      private static $upgradedcodes = [];
 410      /** @var bool basicauth */
 411      protected $basicauth = false;
 412  
 413      /**
 414       * Returns the auth url for OAuth 2.0 request
 415       * @return string the auth url
 416       */
 417      abstract protected function auth_url();
 418  
 419      /**
 420       * Returns the token url for OAuth 2.0 request
 421       * @return string the auth url
 422       */
 423      abstract protected function token_url();
 424  
 425      /**
 426       * Constructor.
 427       *
 428       * @param string $clientid
 429       * @param string $clientsecret
 430       * @param moodle_url $returnurl
 431       * @param string $scope
 432       */
 433      public function __construct($clientid, $clientsecret, moodle_url $returnurl, $scope) {
 434          parent::__construct();
 435          $this->clientid = $clientid;
 436          $this->clientsecret = $clientsecret;
 437          $this->returnurl = $returnurl;
 438          $this->scope = $scope;
 439          $this->accesstoken = $this->get_stored_token();
 440      }
 441  
 442      /**
 443       * Is the user logged in? Note that if this is called
 444       * after the first part of the authorisation flow the token
 445       * is upgraded to an accesstoken.
 446       *
 447       * @return boolean true if logged in
 448       */
 449      public function is_logged_in() {
 450          // Has the token expired?
 451          if (isset($this->accesstoken->expires) && time() >= $this->accesstoken->expires) {
 452              $this->log_out();
 453              return false;
 454          }
 455  
 456          // We have a token so we are logged in.
 457          if (isset($this->accesstoken->token)) {
 458              // Check that the access token has all the requested scopes.
 459              $scopemissing = false;
 460              $scopecheck = ' ' . $this->accesstoken->scope . ' ';
 461  
 462              $requiredscopes = explode(' ', $this->scope);
 463              foreach ($requiredscopes as $requiredscope) {
 464                  if (strpos($scopecheck, ' ' . $requiredscope . ' ') === false) {
 465                      $scopemissing = true;
 466                      break;
 467                  }
 468              }
 469              if (!$scopemissing) {
 470                  return true;
 471              }
 472          }
 473  
 474          // If we've been passed then authorization code generated by the
 475          // authorization server try and upgrade the token to an access token.
 476          $code = optional_param('oauth2code', null, PARAM_RAW);
 477          // Note - sometimes we may call is_logged_in twice in the same request - we don't want to attempt
 478          // to upgrade the same token twice.
 479          if ($code && !in_array($code, self::$upgradedcodes) && $this->upgrade_token($code)) {
 480              return true;
 481          }
 482  
 483          return false;
 484      }
 485  
 486      /**
 487       * Callback url where the request is returned to.
 488       *
 489       * @return moodle_url url of callback
 490       */
 491      public static function callback_url() {
 492          global $CFG;
 493  
 494          return new moodle_url('/admin/oauth2callback.php');
 495      }
 496  
 497      /**
 498       * An additional array of url params to pass with a login request.
 499       *
 500       * @return array of name value pairs.
 501       */
 502      public function get_additional_login_parameters() {
 503          return [];
 504      }
 505  
 506      /**
 507       * Returns the login link for this oauth request
 508       *
 509       * @return moodle_url login url
 510       */
 511      public function get_login_url() {
 512  
 513          $callbackurl = self::callback_url();
 514          $defaultparams = [
 515              'client_id' => $this->clientid,
 516              'response_type' => 'code',
 517              'redirect_uri' => $callbackurl->out(false),
 518              'state' => $this->returnurl->out_as_local_url(false),
 519  
 520          ];
 521          if (!empty($this->scope)) {
 522              // The scope should only be included if a value is set.
 523              // If none provided, the server MUST process the request and provide an appropriate documented response.
 524              // See spec https://tools.ietf.org/html/rfc6749#section-3.3
 525              $defaultparams['scope'] = $this->scope;
 526          }
 527  
 528          $params = array_merge(
 529              $defaultparams,
 530              $this->get_additional_login_parameters()
 531          );
 532  
 533          return new moodle_url($this->auth_url(), $params);
 534      }
 535  
 536      /**
 537       * Given an array of name value pairs - build a valid HTTP POST application/x-www-form-urlencoded string.
 538       *
 539       * @param array $params Name / value pairs.
 540       * @return string POST data.
 541       */
 542      public function build_post_data($params) {
 543          $result = [];
 544          foreach ($params as $name => $value) {
 545              $result[] = urlencode($name) . '=' . urlencode($value);
 546          }
 547          return implode('&', $result);
 548      }
 549  
 550      /**
 551       * Upgrade a authorization token from oauth 2.0 to an access token
 552       *
 553       * @param string $code the code returned from the oauth authenticaiton
 554       * @return boolean true if token is upgraded succesfully
 555       */
 556      public function upgrade_token($code) {
 557          $callbackurl = self::callback_url();
 558          $params = array('code' => $code,
 559              'grant_type' => 'authorization_code',
 560              'redirect_uri' => $callbackurl->out(false),
 561          );
 562  
 563          if ($this->basicauth) {
 564              $idsecret = urlencode($this->clientid) . ':' . urlencode($this->clientsecret);
 565              $this->setHeader('Authorization: Basic ' . base64_encode($idsecret));
 566          } else {
 567              $params['client_id'] = $this->clientid;
 568              $params['client_secret'] = $this->clientsecret;
 569          }
 570  
 571          // Requests can either use http GET or POST.
 572          if ($this->use_http_get()) {
 573              $response = $this->get($this->token_url(), $params);
 574          } else {
 575              $response = $this->post($this->token_url(), $this->build_post_data($params));
 576          }
 577  
 578          if ($this->info['http_code'] !== 200) {
 579              throw new moodle_exception('Could not upgrade oauth token');
 580          }
 581  
 582          $r = json_decode($response);
 583  
 584          if (is_null($r)) {
 585              throw new moodle_exception("Could not decode JSON token response");
 586          }
 587  
 588          if (!empty($r->error)) {
 589              throw new moodle_exception($r->error . ' ' . $r->error_description);
 590          }
 591  
 592          if (!isset($r->access_token)) {
 593              return false;
 594          }
 595  
 596          if (isset($r->refresh_token)) {
 597              $this->refreshtoken = $r->refresh_token;
 598          }
 599  
 600          // Store the token an expiry time.
 601          $accesstoken = new stdClass;
 602          $accesstoken->token = $r->access_token;
 603          if (isset($r->expires_in)) {
 604              // Expires 10 seconds before actual expiry.
 605              $accesstoken->expires = (time() + ($r->expires_in - 10));
 606          }
 607          $accesstoken->scope = $this->scope;
 608          // Also add the scopes.
 609          self::$upgradedcodes[] = $code;
 610          $this->store_token($accesstoken);
 611  
 612          return true;
 613      }
 614  
 615      /**
 616       * Logs out of a oauth request, clearing any stored tokens
 617       */
 618      public function log_out() {
 619          $this->store_token(null);
 620      }
 621  
 622      /**
 623       * Make a HTTP request, adding the access token we have
 624       *
 625       * @param string $url The URL to request
 626       * @param array $options
 627       * @param mixed $acceptheader mimetype (as string) or false to skip sending an accept header.
 628       * @return bool
 629       */
 630      protected function request($url, $options = array(), $acceptheader = 'application/json') {
 631          $murl = new moodle_url($url);
 632  
 633          if ($this->accesstoken) {
 634              if ($this->use_http_get()) {
 635                  // If using HTTP GET add as a parameter.
 636                  $murl->param('access_token', $this->accesstoken->token);
 637              } else {
 638                  $this->setHeader('Authorization: Bearer '.$this->accesstoken->token);
 639              }
 640          }
 641  
 642          if ($acceptheader) {
 643              $this->setHeader('Accept: ' . $acceptheader);
 644          }
 645  
 646          $response = parent::request($murl->out(false), $options);
 647  
 648          $this->resetHeader();
 649  
 650          return $response;
 651      }
 652  
 653      /**
 654       * Multiple HTTP Requests
 655       * This function could run multi-requests in parallel.
 656       *
 657       * @param array $requests An array of files to request
 658       * @param array $options An array of options to set
 659       * @return array An array of results
 660       */
 661      protected function multi($requests, $options = array()) {
 662          if ($this->accesstoken) {
 663              $this->setHeader('Authorization: Bearer '.$this->accesstoken->token);
 664          }
 665          return parent::multi($requests, $options);
 666      }
 667  
 668      /**
 669       * Returns the tokenname for the access_token to be stored
 670       * through multiple requests.
 671       *
 672       * The default implentation is to use the classname combiend
 673       * with the scope.
 674       *
 675       * @return string tokenname for prefernce storage
 676       */
 677      protected function get_tokenname() {
 678          // This is unusual but should work for most purposes.
 679          return get_class($this).'-'.md5($this->scope);
 680      }
 681  
 682      /**
 683       * Store a token between requests. Currently uses
 684       * session named by get_tokenname
 685       *
 686       * @param stdClass|null $token token object to store or null to clear
 687       */
 688      protected function store_token($token) {
 689          global $SESSION;
 690  
 691          $this->accesstoken = $token;
 692          $name = $this->get_tokenname();
 693  
 694          if ($token !== null) {
 695              $SESSION->{$name} = $token;
 696          } else {
 697              unset($SESSION->{$name});
 698          }
 699      }
 700  
 701      /**
 702       * Get a refresh token!!!
 703       *
 704       * @return string
 705       */
 706      public function get_refresh_token() {
 707          return $this->refreshtoken;
 708      }
 709  
 710      /**
 711       * Retrieve a token stored.
 712       *
 713       * @return stdClass|null token object
 714       */
 715      protected function get_stored_token() {
 716          global $SESSION;
 717  
 718          $name = $this->get_tokenname();
 719  
 720          if (isset($SESSION->{$name})) {
 721              return $SESSION->{$name};
 722          }
 723  
 724          return null;
 725      }
 726  
 727      /**
 728       * Get access token.
 729       *
 730       * This is just a getter to read the private property.
 731       *
 732       * @return string
 733       */
 734      public function get_accesstoken() {
 735          return $this->accesstoken;
 736      }
 737  
 738      /**
 739       * Get the client ID.
 740       *
 741       * This is just a getter to read the private property.
 742       *
 743       * @return string
 744       */
 745      public function get_clientid() {
 746          return $this->clientid;
 747      }
 748  
 749      /**
 750       * Get the client secret.
 751       *
 752       * This is just a getter to read the private property.
 753       *
 754       * @return string
 755       */
 756      public function get_clientsecret() {
 757          return $this->clientsecret;
 758      }
 759  
 760      /**
 761       * Should HTTP GET be used instead of POST?
 762       * Some APIs do not support POST and want oauth to use
 763       * GET instead (with the auth_token passed as a GET param).
 764       *
 765       * @return bool true if GET should be used
 766       */
 767      protected function use_http_get() {
 768          return false;
 769      }
 770  }