Client::setToken()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
/**
3
 * Part of the Joomla Framework OAuth1 Package
4
 *
5
 * @copyright  Copyright (C) 2005 - 2018 Open Source Matters, Inc. All rights reserved.
6
 * @license    GNU General Public License version 2 or later; see LICENSE
7
 */
8
9
namespace Joomla\Oauth1;
10
11
use Joomla\Application\AbstractWebApplication;
12
use Joomla\Http\Http;
13
use Joomla\Input\Input;
14
15
/**
16
 * Joomla Framework class for interacting with an OAuth 1.0 and 1.0a server.
17
 *
18
 * @since  1.0
19
 */
20
abstract class Client
21
{
22
	/**
23
	 * @var    array  Options for the Client object.
24
	 * @since  1.0
25
	 */
26
	protected $options;
27
28
	/**
29
	 * @var    array  Contains access token key, secret and verifier.
30
	 * @since  1.0
31
	 */
32
	protected $token = array();
33
34
	/**
35
	 * @var    Http  The HTTP client object to use in sending HTTP requests.
36
	 * @since  1.0
37
	 */
38
	protected $client;
39
40
	/**
41
	 * @var    Input The input object to use in retrieving GET/POST data.
42
	 * @since  1.0
43
	 */
44
	protected $input;
45
46
	/**
47
	 * @var    AbstractWebApplication  The application object to send HTTP headers for redirects.
48
	 * @since  1.0
49
	 */
50
	protected $application;
51
52
	/**
53
	 * @var    string  Selects which version of OAuth to use: 1.0 or 1.0a.
54
	 * @since  1.0
55
	 */
56
	protected $version;
57
58
	/**
59
	 * Constructor.
60
	 *
61
	 * @param   array                   $options      OAuth1 Client options array.
62
	 * @param   Http                    $client       The HTTP client object.
63
	 * @param   Input                   $input        The input object
64
	 * @param   AbstractWebApplication  $application  The application object
65
	 * @param   string                  $version      Specify the OAuth version. By default we are using 1.0a.
66
	 *
67
	 * @since   1.0
68
	 */
69
	public function __construct($options = array(), Http $client, Input $input, AbstractWebApplication $application, $version = '1.0a')
70
	{
71
		$this->options     = $options;
72
		$this->client      = $client;
73
		$this->input       = $input;
74
		$this->application = $application;
75
		$this->version     = $version;
76
	}
77
78
	/**
79
	 * Method to form the oauth flow.
80
	 *
81
	 * @return  string  The access token.
82
	 *
83
	 * @since   1.0
84
	 * @throws  \DomainException
85
	 */
86
	public function authenticate()
87
	{
88
		// Already got some credentials stored?
89
		if ($this->token)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->token of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
90
		{
91
			$response = $this->verifyCredentials();
92
93
			if ($response)
0 ignored issues
show
Bug Best Practice introduced by
The expression $response of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
94
			{
95
				return $this->token;
96
			}
97
98
			$this->token = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $token.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
99
		}
100
101
		// Check for callback.
102
		if (strcmp($this->version, '1.0a') === 0)
103
		{
104
			$verifier = $this->input->get('oauth_verifier');
105
		}
106
		else
107
		{
108
			$verifier = $this->input->get('oauth_token');
109
		}
110
111
		if (empty($verifier))
112
		{
113
			// Generate a request token.
114
			$this->generateRequestToken();
115
116
			// Authenticate the user and authorise the app.
117
			$this->authorise();
118
		}
119
120
		// Callback
121
		else
122
		{
123
			$session = $this->application->getSession();
124
125
			// Get token form session.
126
			$this->token = array('key' => $session->get('oauth_token.key', null), 'secret' => $session->get('oauth_token.secret', null));
127
128
			// Verify the returned request token.
129
			if (strcmp($this->token['key'], $this->input->get('oauth_token')) !== 0)
130
			{
131
				throw new \DomainException('Bad session!');
132
			}
133
134
			// Set token verifier for 1.0a.
135
			if (strcmp($this->version, '1.0a') === 0)
136
			{
137
				$this->token['verifier'] = $this->input->get('oauth_verifier');
138
			}
139
140
			// Generate access token.
141
			$this->generateAccessToken();
142
143
			// Return the access token.
144
			return $this->token;
145
		}
146
	}
147
148
	/**
149
	 * Method used to get a request token.
150
	 *
151
	 * @return  void
152
	 *
153
	 * @since   1.1.2
154
	 * @throws  \DomainException
155
	 */
156
	private function generateRequestToken()
157
	{
158
		// Set the callback URL.
159
		if ($this->getOption('callback'))
160
		{
161
			$parameters = array(
162
				'oauth_callback' => $this->getOption('callback'),
163
			);
164
		}
165
		else
166
		{
167
			$parameters = array();
168
		}
169
170
		// Make an OAuth request for the Request Token.
171
		$response = $this->oauthRequest($this->getOption('requestTokenURL'), 'POST', $parameters);
172
173
		parse_str($response->body, $params);
174
175
		if (strcmp($this->version, '1.0a') === 0 && strcmp($params['oauth_callback_confirmed'], 'true') !== 0)
176
		{
177
			throw new \DomainException('Bad request token!');
178
		}
179
180
		// Save the request token.
181
		$this->token = array('key' => $params['oauth_token'], 'secret' => $params['oauth_token_secret']);
182
183
		// Save the request token in session
184
		$session = $this->application->getSession();
185
		$session->set('oauth_token.key', $this->token['key']);
186
		$session->set('oauth_token.secret', $this->token['secret']);
187
	}
188
189
	/**
190
	 * Method used to authorise the application.
191
	 *
192
	 * @return  void
193
	 *
194
	 * @since   1.1.2
195
	 */
196
	private function authorise()
197
	{
198
		$url = $this->getOption('authoriseURL') . '?oauth_token=' . $this->token['key'];
199
200
		if ($this->getOption('scope'))
201
		{
202
			$scope = \is_array($this->getOption('scope')) ? implode(' ', $this->getOption('scope')) : $this->getOption('scope');
203
			$url .= '&scope=' . urlencode($scope);
204
		}
205
206
		if ($this->getOption('sendheaders'))
207
		{
208
			$this->application->redirect($url);
209
		}
210
	}
211
212
	/**
213
	 * Method used to get an access token.
214
	 *
215
	 * @return  void
216
	 *
217
	 * @since   1.1.2
218
	 */
219
	private function generateAccessToken()
220
	{
221
		// Set the parameters.
222
		$parameters = array(
223
			'oauth_token' => $this->token['key'],
224
		);
225
226
		if (strcmp($this->version, '1.0a') === 0)
227
		{
228
			$parameters = array_merge($parameters, array('oauth_verifier' => $this->token['verifier']));
229
		}
230
231
		// Make an OAuth request for the Access Token.
232
		$response = $this->oauthRequest($this->getOption('accessTokenURL'), 'POST', $parameters);
233
234
		parse_str($response->body, $params);
235
236
		// Save the access token.
237
		$this->token = array('key' => $params['oauth_token'], 'secret' => $params['oauth_token_secret']);
238
	}
239
240
	/**
241
	 * Method used to make an OAuth request.
242
	 *
243
	 * @param   string  $url         The request URL.
244
	 * @param   string  $method      The request method.
245
	 * @param   array   $parameters  Array containing request parameters.
246
	 * @param   mixed   $data        The POST request data.
247
	 * @param   array   $headers     An array of name-value pairs to include in the header of the request
248
	 *
249
	 * @return  object  The Response object.
250
	 *
251
	 * @since   1.0
252
	 * @throws  \DomainException
253
	 */
254
	public function oauthRequest($url, $method, $parameters, $data = array(), $headers = array())
255
	{
256
		// Set the parameters.
257
		$defaults = array(
258
			'oauth_consumer_key'     => $this->getOption('consumer_key'),
259
			'oauth_signature_method' => 'HMAC-SHA1',
260
			'oauth_version'          => '1.0',
261
			'oauth_nonce'            => $this->generateNonce(),
262
			'oauth_timestamp'        => time(),
263
		);
264
265
		$parameters = array_merge($parameters, $defaults);
266
267
		// Do not encode multipart parameters. Do not include $data in the signature if $data is not array.
268
		if (isset($headers['Content-Type']) && strpos($headers['Content-Type'], 'multipart/form-data') !== false || !\is_array($data))
269
		{
270
			$oauthHeaders = $parameters;
271
		}
272
		else
273
		{
274
			// Use all parameters for the signature.
275
			$oauthHeaders = array_merge($parameters, $data);
276
		}
277
278
		// Sign the request.
279
		$oauthHeaders = $this->signRequest($url, $method, $oauthHeaders);
280
281
		// Get parameters for the Authorisation header.
282
		if (\is_array($data))
283
		{
284
			$oauthHeaders = array_diff_key($oauthHeaders, $data);
285
		}
286
287
		// Send the request.
288
		switch ($method)
289
		{
290 View Code Duplication
			case 'GET':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
291
				$url      = $this->toUrl($url, $data);
292
				$response = $this->client->get($url, array('Authorization' => $this->createHeader($oauthHeaders)));
293
294
				break;
295
296 View Code Duplication
			case 'POST':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
297
				$headers  = array_merge($headers, array('Authorization' => $this->createHeader($oauthHeaders)));
298
				$response = $this->client->post($url, $data, $headers);
299
300
				break;
301
302 View Code Duplication
			case 'PUT':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
303
				$headers  = array_merge($headers, array('Authorization' => $this->createHeader($oauthHeaders)));
304
				$response = $this->client->put($url, $data, $headers);
305
306
				break;
307
308 View Code Duplication
			case 'DELETE':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
309
				$headers  = array_merge($headers, array('Authorization' => $this->createHeader($oauthHeaders)));
310
				$response = $this->client->delete($url, $headers);
311
312
				break;
313
		}
314
315
		// Validate the response code.
316
		$this->validateResponse($url, $response);
0 ignored issues
show
Bug introduced by
The variable $response does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Documentation introduced by
$response is of type object<Joomla\Http\Response>, but the function expects a object<Joomla\Oauth1\Response>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
317
318
		return $response;
319
	}
320
321
	/**
322
	 * Method to validate a response.
323
	 *
324
	 * @param   string    $url       The request URL.
325
	 * @param   Response  $response  The response to validate.
326
	 *
327
	 * @return  void
328
	 *
329
	 * @since   1.0
330
	 * @throws  \DomainException
331
	 */
332
	abstract public function validateResponse($url, $response);
333
334
	/**
335
	 * Method used to create the header for the POST request.
336
	 *
337
	 * @param   array  $parameters  Array containing request parameters.
338
	 *
339
	 * @return  string  The header.
340
	 *
341
	 * @since   1.1.2
342
	 */
343
	private function createHeader($parameters)
344
	{
345
		$header = 'OAuth ';
346
347
		foreach ($parameters as $key => $value)
348
		{
349
			if (!strcmp($header, 'OAuth '))
350
			{
351
				$header .= $key . '="' . $this->safeEncode($value) . '"';
352
			}
353
			else
354
			{
355
				$header .= ', ' . $key . '="' . $value . '"';
356
			}
357
		}
358
359
		return $header;
360
	}
361
362
	/**
363
	 * Method to create the URL formed string with the parameters.
364
	 *
365
	 * @param   string  $url         The request URL.
366
	 * @param   array   $parameters  Array containing request parameters.
367
	 *
368
	 * @return  string  The formed URL.
369
	 *
370
	 * @since   1.0
371
	 */
372
	public function toUrl($url, $parameters)
373
	{
374
		foreach ($parameters as $key => $value)
375
		{
376
			if (\is_array($value))
377
			{
378
				foreach ($value as $k => $v)
379
				{
380
					if (strpos($url, '?') === false)
381
					{
382
						$url .= '?' . $key . '=' . $v;
383
					}
384
					else
385
					{
386
						$url .= '&' . $key . '=' . $v;
387
					}
388
				}
389
			}
390
			else
391
			{
392
				if (strpos($value, ' ') !== false)
393
				{
394
					$value = $this->safeEncode($value);
395
				}
396
397
				if (strpos($url, '?') === false)
398
				{
399
					$url .= '?' . $key . '=' . $value;
400
				}
401
				else
402
				{
403
					$url .= '&' . $key . '=' . $value;
404
				}
405
			}
406
		}
407
408
		return $url;
409
	}
410
411
	/**
412
	 * Method used to sign requests.
413
	 *
414
	 * @param   string  $url         The URL to sign.
415
	 * @param   string  $method      The request method.
416
	 * @param   array   $parameters  Array containing request parameters.
417
	 *
418
	 * @return  array  The array containing the request parameters, including signature.
419
	 *
420
	 * @since   1.1.2
421
	 */
422
	private function signRequest($url, $method, $parameters)
423
	{
424
		// Create the signature base string.
425
		$base = $this->baseString($url, $method, $parameters);
426
427
		$parameters['oauth_signature'] = $this->safeEncode(
428
			base64_encode(
429
				hash_hmac('sha1', $base, $this->prepareSigningKey(), true)
430
			)
431
		);
432
433
		return $parameters;
434
	}
435
436
	/**
437
	 * Prepare the signature base string.
438
	 *
439
	 * @param   string  $url         The URL to sign.
440
	 * @param   string  $method      The request method.
441
	 * @param   array   $parameters  Array containing request parameters.
442
	 *
443
	 * @return  string  The base string.
444
	 *
445
	 * @since   1.1.2
446
	 */
447
	private function baseString($url, $method, $parameters)
448
	{
449
		// Sort the parameters alphabetically
450
		uksort($parameters, 'strcmp');
451
452
		// Encode parameters.
453
		foreach ($parameters as $key => $value)
454
		{
455
			$key = $this->safeEncode($key);
456
457
			if (\is_array($value))
458
			{
459
				foreach ($value as $k => $v)
460
				{
461
					$v    = $this->safeEncode($v);
462
					$kv[] = "{$key}={$v}";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$kv was never initialized. Although not strictly required by PHP, it is generally a good practice to add $kv = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
463
				}
464
			}
465
			else
466
			{
467
				$value = $this->safeEncode($value);
468
				$kv[]  = "{$key}={$value}";
0 ignored issues
show
Bug introduced by
The variable $kv does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
469
			}
470
		}
471
472
		// Form the parameter string.
473
		$params = implode('&', $kv);
474
475
		// Signature base string elements.
476
		$base = array(
477
			$method,
478
			$url,
479
			$params,
480
		);
481
482
		// Return the base string.
483
		return implode('&', $this->safeEncode($base));
484
	}
485
486
	/**
487
	 * Encodes the string or array passed in a way compatible with OAuth.
488
	 * If an array is passed each array value will will be encoded.
489
	 *
490
	 * @param   mixed  $data  The scalar or array to encode.
491
	 *
492
	 * @return  string  $data encoded in a way compatible with OAuth.
493
	 *
494
	 * @since   1.0
495
	 */
496
	public function safeEncode($data)
497
	{
498
		if (\is_array($data))
499
		{
500
			return array_map(array($this, 'safeEncode'), $data);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array_map(array($... 'safeEncode'), $data); (array) is incompatible with the return type documented by Joomla\Oauth1\Client::safeEncode of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
501
		}
502
503
		if (is_scalar($data))
504
		{
505
			return str_ireplace(
506
				array('+', '%7E'),
507
				array(' ', '~'),
508
				rawurlencode($data)
509
			);
510
		}
511
512
		return '';
513
	}
514
515
	/**
516
	 * Method used to generate the current nonce.
517
	 *
518
	 * @return  string  The current nonce.
519
	 *
520
	 * @since   1.0
521
	 */
522
	public static function generateNonce()
523
	{
524
		$mt   = microtime();
525
		$rand = random_bytes(16);
526
527
		// The md5s look nicer than numbers.
528
		return md5($mt . $rand);
529
	}
530
531
	/**
532
	 * Prepares the OAuth signing key.
533
	 *
534
	 * @return  string  The prepared signing key.
535
	 *
536
	 * @since   1.1.2
537
	 */
538
	private function prepareSigningKey()
539
	{
540
		return $this->safeEncode($this->getOption('consumer_secret')) . '&' . $this->safeEncode(($this->token) ? $this->token['secret'] : '');
541
	}
542
543
	/**
544
	 * Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful;
545
	 * returns a 401 status code and an error message if not.
546
	 *
547
	 * @return  array  The decoded JSON response
548
	 *
549
	 * @since   1.0
550
	 */
551
	abstract public function verifyCredentials();
552
553
	/**
554
	 * Get an option from the OAuth1 Client instance.
555
	 *
556
	 * @param   string  $key  The name of the option to get
557
	 *
558
	 * @return  mixed  The option value
559
	 *
560
	 * @since   1.0
561
	 */
562
	public function getOption($key)
563
	{
564
		return isset($this->options[$key]) ? $this->options[$key] : null;
565
	}
566
567
	/**
568
	 * Set an option for the OAuth1 Client instance.
569
	 *
570
	 * @param   string  $key    The name of the option to set
571
	 * @param   mixed   $value  The option value to set
572
	 *
573
	 * @return  Client  This object for method chaining
574
	 *
575
	 * @since   1.0
576
	 */
577
	public function setOption($key, $value)
578
	{
579
		$this->options[$key] = $value;
580
581
		return $this;
582
	}
583
584
	/**
585
	 * Get the oauth token key or secret.
586
	 *
587
	 * @return  array  The oauth token key and secret.
588
	 *
589
	 * @since   1.0
590
	 */
591
	public function getToken()
592
	{
593
		return $this->token;
594
	}
595
596
	/**
597
	 * Set the oauth token.
598
	 *
599
	 * @param   array  $token  The access token key and secret.
600
	 *
601
	 * @return  Client  This object for method chaining.
602
	 *
603
	 * @since   1.0
604
	 */
605
	public function setToken($token)
606
	{
607
		$this->token = $token;
608
609
		return $this;
610
	}
611
}
612