GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( a15ec7...95b071 )
by Freek
17s
created

Client::getAccessToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Spatie\Dropbox;
4
5
use Exception;
6
use GuzzleHttp\Psr7;
7
use GuzzleHttp\Psr7\PumpStream;
8
use GuzzleHttp\Psr7\StreamWrapper;
9
use Psr\Http\Message\StreamInterface;
10
use GuzzleHttp\Client as GuzzleClient;
11
use Psr\Http\Message\ResponseInterface;
12
use GuzzleHttp\Exception\ClientException;
13
use Spatie\Dropbox\Exceptions\BadRequest;
14
use GuzzleHttp\Exception\RequestException;
15
16
class Client
17
{
18
    const THUMBNAIL_FORMAT_JPEG = 'jpeg';
19
    const THUMBNAIL_FORMAT_PNG = 'png';
20
21
    const THUMBNAIL_SIZE_XS = 'w32h32';
22
    const THUMBNAIL_SIZE_S = 'w64h64';
23
    const THUMBNAIL_SIZE_M = 'w128h128';
24
    const THUMBNAIL_SIZE_L = 'w640h480';
25
    const THUMBNAIL_SIZE_XL = 'w1024h768';
26
27
    const MAX_CHUNK_SIZE = 1024 * 1024 * 150;
28
29
    const UPLOAD_SESSION_START = 0;
30
    const UPLOAD_SESSION_APPEND = 1;
31
32
    /** @var string */
33
    protected $accessToken;
34
35
    /** @var \GuzzleHttp\Client */
36
    protected $client;
37
38
    /** @var int */
39
    protected $maxChunkSize;
40
41
    /** @var int */
42
    protected $maxUploadChunkRetries;
43
44
    /**
45
     * @param string $accessToken
46
     * @param GuzzleClient|null $client
47
     * @param int $maxChunkSize Set max chunk size per request (determines when to switch from "one shot upload" to upload session and defines chunk size for uploads via session).
48
     * @param int $maxUploadChunkRetries How many times to retry an upload session start or append after RequestException.
49
     */
50
    public function __construct(string $accessToken, GuzzleClient $client = null, int $maxChunkSize = self::MAX_CHUNK_SIZE, int $maxUploadChunkRetries = 0)
51
    {
52
        $this->accessToken = $accessToken;
53
54
        $this->client = $client ?? new GuzzleClient();
55
56
        $this->maxChunkSize = ($maxChunkSize < self::MAX_CHUNK_SIZE ? ($maxChunkSize > 1 ? $maxChunkSize : 1) : self::MAX_CHUNK_SIZE);
57
        $this->maxUploadChunkRetries = $maxUploadChunkRetries;
58
    }
59
60
    /**
61
     * Copy a file or folder to a different location in the user's Dropbox.
62
     *
63
     * If the source path is a folder all its contents will be copied.
64
     *
65
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-copy_v2
66
     */
67 View Code Duplication
    public function copy(string $fromPath, string $toPath): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
68
    {
69
        $parameters = [
70
            'from_path' => $this->normalizePath($fromPath),
71
            'to_path' => $this->normalizePath($toPath),
72
        ];
73
74
        return $this->rpcEndpointRequest('files/copy_v2', $parameters);
75
    }
76
77
    /**
78
     * Create a folder at a given path.
79
     *
80
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-create_folder
81
     */
82
    public function createFolder(string $path): array
83
    {
84
        $parameters = [
85
            'path' => $this->normalizePath($path),
86
        ];
87
88
        $object = $this->rpcEndpointRequest('files/create_folder', $parameters);
89
90
        $object['.tag'] = 'folder';
91
92
        return $object;
93
    }
94
95
    /**
96
     * Create a shared link with custom settings.
97
     *
98
     * If no settings are given then the default visibility is RequestedVisibility.public.
99
     * The resolved visibility, though, may depend on other aspects such as team and
100
     * shared folder settings). Only for paid users.
101
     *
102
     * @link https://www.dropbox.com/developers/documentation/http/documentation#sharing-create_shared_link_with_settings
103
     */
104
    public function createSharedLinkWithSettings(string $path, array $settings = [])
105
    {
106
        $parameters = [
107
            'path' => $this->normalizePath($path),
108
            'settings' => $settings,
109
        ];
110
111
        return $this->rpcEndpointRequest('sharing/create_shared_link_with_settings', $parameters);
112
    }
113
114
    /**
115
     * List shared links.
116
     *
117
     * For empty path returns a list of all shared links. For non-empty path
118
     * returns a list of all shared links with access to the given path.
119
     *
120
     * If direct_only is set true, only direct links to the path will be returned, otherwise
121
     * it may return link to the path itself and parent folders as described on docs.
122
     *
123
     * @link https://www.dropbox.com/developers/documentation/http/documentation#sharing-list_shared_links
124
     */
125
    public function listSharedLinks(string $path = null, bool $direct_only = false, string $cursor = null): array
126
    {
127
        $parameters = [
128
            'path' => $path ? $this->normalizePath($path) : null,
129
            'cursor' => $cursor,
130
            'direct_only' => $direct_only,
131
        ];
132
133
        $body = $this->rpcEndpointRequest('sharing/list_shared_links', $parameters);
134
135
        return $body['links'];
136
    }
137
138
    /**
139
     * Delete the file or folder at a given path.
140
     *
141
     * If the path is a folder, all its contents will be deleted too.
142
     * A successful response indicates that the file or folder was deleted.
143
     *
144
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-delete
145
     */
146
    public function delete(string $path): array
147
    {
148
        $parameters = [
149
            'path' => $this->normalizePath($path),
150
        ];
151
152
        return $this->rpcEndpointRequest('files/delete', $parameters);
153
    }
154
155
    /**
156
     * Download a file from a user's Dropbox.
157
     *
158
     * @param string $path
159
     *
160
     * @return resource
161
     *
162
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-download
163
     */
164
    public function download(string $path)
165
    {
166
        $arguments = [
167
            'path' => $this->normalizePath($path),
168
        ];
169
170
        $response = $this->contentEndpointRequest('files/download', $arguments);
171
172
        return StreamWrapper::getResource($response->getBody());
173
    }
174
175
    /**
176
     * Returns the metadata for a file or folder.
177
     *
178
     * Note: Metadata for the root folder is unsupported.
179
     *
180
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_metadata
181
     */
182
    public function getMetadata(string $path): array
183
    {
184
        $parameters = [
185
            'path' => $this->normalizePath($path),
186
        ];
187
188
        return $this->rpcEndpointRequest('files/get_metadata', $parameters);
189
    }
190
191
    /**
192
     * Get a temporary link to stream content of a file.
193
     *
194
     * This link will expire in four hours and afterwards you will get 410 Gone.
195
     * Content-Type of the link is determined automatically by the file's mime type.
196
     *
197
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_temporary_link
198
     */
199 View Code Duplication
    public function getTemporaryLink(string $path): string
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
200
    {
201
        $parameters = [
202
            'path' => $this->normalizePath($path),
203
        ];
204
205
        $body = $this->rpcEndpointRequest('files/get_temporary_link', $parameters);
206
207
        return $body['link'];
208
    }
209
210
    /**
211
     * Get a thumbnail for an image.
212
     *
213
     * This method currently supports files with the following file extensions:
214
     * jpg, jpeg, png, tiff, tif, gif and bmp.
215
     *
216
     * Photos that are larger than 20MB in size won't be converted to a thumbnail.
217
     *
218
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_thumbnail
219
     */
220
    public function getThumbnail(string $path, string $format = 'jpeg', string $size = 'w64h64'): string
221
    {
222
        $arguments = [
223
            'path' => $this->normalizePath($path),
224
            'format' => $format,
225
            'size' => $size,
226
        ];
227
228
        $response = $this->contentEndpointRequest('files/get_thumbnail', $arguments);
229
230
        return (string) $response->getBody();
231
    }
232
233
    /**
234
     * Starts returning the contents of a folder.
235
     *
236
     * If the result's ListFolderResult.has_more field is true, call
237
     * list_folder/continue with the returned ListFolderResult.cursor to retrieve more entries.
238
     *
239
     * Note: auth.RateLimitError may be returned if multiple list_folder or list_folder/continue calls
240
     * with same parameters are made simultaneously by same API app for same user. If your app implements
241
     * retry logic, please hold off the retry until the previous request finishes.
242
     *
243
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder
244
     */
245 View Code Duplication
    public function listFolder(string $path = '', bool $recursive = false): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
246
    {
247
        $parameters = [
248
            'path' => $this->normalizePath($path),
249
            'recursive' => $recursive,
250
        ];
251
252
        return $this->rpcEndpointRequest('files/list_folder', $parameters);
253
    }
254
255
    /**
256
     * Once a cursor has been retrieved from list_folder, use this to paginate through all files and
257
     * retrieve updates to the folder, following the same rules as documented for list_folder.
258
     *
259
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder-continue
260
     */
261
    public function listFolderContinue(string $cursor = ''): array
262
    {
263
        return $this->rpcEndpointRequest('files/list_folder/continue', compact('cursor'));
264
    }
265
266
    /**
267
     * Move a file or folder to a different location in the user's Dropbox.
268
     *
269
     * If the source path is a folder all its contents will be moved.
270
     *
271
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-move_v2
272
     */
273 View Code Duplication
    public function move(string $fromPath, string $toPath): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
274
    {
275
        $parameters = [
276
            'from_path' => $this->normalizePath($fromPath),
277
            'to_path' => $this->normalizePath($toPath),
278
        ];
279
280
        return $this->rpcEndpointRequest('files/move_v2', $parameters);
281
    }
282
283
    /**
284
     * The file should be uploaded in chunks if it size exceeds the 150 MB threshold
285
     * or if the resource size could not be determined (eg. a popen() stream).
286
     *
287
     * @param string|resource $contents
288
     *
289
     * @return bool
290
     */
291
    protected function shouldUploadChunked($contents): bool
292
    {
293
        $size = is_string($contents) ? strlen($contents) : fstat($contents)['size'];
294
295
        if ($this->isPipe($contents)) {
296
            return true;
297
        }
298
299
        if ($size === null) {
300
            return true;
301
        }
302
303
        return $size > $this->maxChunkSize;
304
    }
305
306
    /**
307
     * Check if the contents is a pipe stream (not seekable, no size defined).
308
     *
309
     * @param string|resource $contents
310
     *
311
     * @return bool
312
     */
313
    protected function isPipe($contents): bool
314
    {
315
        return is_resource($contents) ? (fstat($contents)['mode'] & 010000) != 0 : false;
316
    }
317
318
    /**
319
     * Create a new file with the contents provided in the request.
320
     *
321
     * Do not use this to upload a file larger than 150 MB. Instead, create an upload session with upload_session/start.
322
     *
323
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload
324
     *
325
     * @param string $path
326
     * @param string|resource $contents
327
     * @param string $mode
328
     *
329
     * @return array
330
     */
331
    public function upload(string $path, $contents, $mode = 'add'): array
332
    {
333
        if ($this->shouldUploadChunked($contents)) {
334
            return $this->uploadChunked($path, $contents, $mode);
335
        }
336
337
        $arguments = [
338
            'path' => $this->normalizePath($path),
339
            'mode' => $mode,
340
        ];
341
342
        $response = $this->contentEndpointRequest('files/upload', $arguments, $contents);
343
344
        $metadata = json_decode($response->getBody(), true);
345
346
        $metadata['.tag'] = 'file';
347
348
        return $metadata;
349
    }
350
351
    /**
352
     * Upload file split in chunks. This allows uploading large files, since
353
     * Dropbox API v2 limits the content size to 150MB.
354
     *
355
     * The chunk size will affect directly the memory usage, so be careful.
356
     * Large chunks tends to speed up the upload, while smaller optimizes memory usage.
357
     *
358
     * @param string $path
359
     * @param string|resource $contents
360
     * @param string $mode
361
     * @param int $chunkSize
362
     *
363
     * @return array
364
     */
365
    public function uploadChunked(string $path, $contents, $mode = 'add', $chunkSize = null): array
366
    {
367
        if ($chunkSize === null || $chunkSize > $this->maxChunkSize) {
368
            $chunkSize = $this->maxChunkSize;
369
        }
370
371
        $stream = $this->getStream($contents);
372
373
        $cursor = $this->uploadChunk(self::UPLOAD_SESSION_START, $stream, $chunkSize, null);
0 ignored issues
show
Bug introduced by
It seems like $stream defined by $this->getStream($contents) on line 371 can also be of type object<GuzzleHttp\Psr7\PumpStream>; however, Spatie\Dropbox\Client::uploadChunk() does only seem to accept object<GuzzleHttp\Psr7\Stream>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
374
375
        while (! $stream->eof()) {
376
            $cursor = $this->uploadChunk(self::UPLOAD_SESSION_APPEND, $stream, $chunkSize, $cursor);
377
        }
378
379
        return $this->uploadSessionFinish('', $cursor, $path, $mode);
380
    }
381
382
    /**
383
     * @param int $type
384
     * @param Psr7\Stream $stream
385
     * @param int $chunkSize
386
     * @param \Spatie\Dropbox\UploadSessionCursor|null $cursor
387
     * @return \Spatie\Dropbox\UploadSessionCursor
388
     * @throws Exception
389
     */
390
    protected function uploadChunk($type, &$stream, $chunkSize, $cursor = null): UploadSessionCursor
391
    {
392
        $maximumTries = $stream->isSeekable() ? $this->maxUploadChunkRetries : 0;
393
        $pos = $stream->tell();
394
395
        $tries = 0;
396
397
        tryUpload:
398
        try {
399
            $tries++;
400
401
            $chunkStream = new Psr7\LimitStream($stream, $chunkSize, $stream->tell());
402
403
            if ($type === self::UPLOAD_SESSION_START) {
404
                return $this->uploadSessionStart($chunkStream);
405
            }
406
407
            if ($type === self::UPLOAD_SESSION_APPEND && $cursor !== null) {
408
                return $this->uploadSessionAppend($chunkStream, $cursor);
409
            }
410
411
            throw new Exception('Invalid type');
412
        } catch (RequestException $exception) {
413
            if ($tries < $maximumTries) {
414
                // rewind
415
                $stream->seek($pos, SEEK_SET);
416
                goto tryUpload;
417
            }
418
            throw $exception;
419
        }
420
    }
421
422
    /**
423
     * Upload sessions allow you to upload a single file in one or more requests,
424
     * for example where the size of the file is greater than 150 MB.
425
     * This call starts a new upload session with the given data.
426
     *
427
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-start
428
     *
429
     * @param string|StreamInterface $contents
430
     * @param bool $close
431
     *
432
     * @return UploadSessionCursor
433
     */
434
    public function uploadSessionStart($contents, bool $close = false): UploadSessionCursor
435
    {
436
        $arguments = compact('close');
437
438
        $response = json_decode(
439
            $this->contentEndpointRequest('files/upload_session/start', $arguments, $contents)->getBody(),
440
            true
441
        );
442
443
        return new UploadSessionCursor($response['session_id'], ($contents instanceof StreamInterface ? $contents->tell() : strlen($contents)));
444
    }
445
446
    /**
447
     * Append more data to an upload session.
448
     * When the parameter close is set, this call will close the session.
449
     * A single request should not upload more than 150 MB.
450
     *
451
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-append_v2
452
     *
453
     * @param string|StreamInterface $contents
454
     * @param UploadSessionCursor $cursor
455
     * @param bool $close
456
     *
457
     * @return \Spatie\Dropbox\UploadSessionCursor
458
     */
459
    public function uploadSessionAppend($contents, UploadSessionCursor $cursor, bool $close = false): UploadSessionCursor
460
    {
461
        $arguments = compact('cursor', 'close');
462
463
        $pos = $contents instanceof StreamInterface ? $contents->tell() : 0;
464
        $this->contentEndpointRequest('files/upload_session/append_v2', $arguments, $contents);
465
466
        $cursor->offset += $contents instanceof StreamInterface ? ($contents->tell() - $pos) : strlen($contents);
467
468
        return $cursor;
469
    }
470
471
    /**
472
     * Finish an upload session and save the uploaded data to the given file path.
473
     * A single request should not upload more than 150 MB.
474
     *
475
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload_session-finish
476
     *
477
     * @param string|StreamInterface $contents
478
     * @param \Spatie\Dropbox\UploadSessionCursor $cursor
479
     * @param string $path
480
     * @param string|array $mode
481
     * @param bool $autorename
482
     * @param bool $mute
483
     *
484
     * @return array
485
     */
486
    public function uploadSessionFinish($contents, UploadSessionCursor $cursor, string $path, $mode = 'add', $autorename = false, $mute = false): array
487
    {
488
        $arguments = compact('cursor');
489
        $arguments['commit'] = compact('path', 'mode', 'autorename', 'mute');
490
491
        $response = $this->contentEndpointRequest(
492
            'files/upload_session/finish',
493
            $arguments,
494
            ($contents == '') ? null : $contents
495
        );
496
497
        $metadata = json_decode($response->getBody(), true);
498
499
        $metadata['.tag'] = 'file';
500
501
        return $metadata;
502
    }
503
504
    /**
505
     * Get Account Info for current authenticated user.
506
     *
507
     * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
508
     *
509
     * @return array
510
     */
511
    public function getAccountInfo(): array
512
    {
513
        return $this->rpcEndpointRequest('users/get_current_account');
514
    }
515
516
    /**
517
     * Revoke current access token.
518
     *
519
     * @link https://www.dropbox.com/developers/documentation/http/documentation#auth-token-revoke
520
     */
521
    public function revokeToken()
522
    {
523
        $this->rpcEndpointRequest('auth/token/revoke');
524
    }
525
526
    protected function normalizePath(string $path): string
527
    {
528
        if (preg_match("/^id:.*|^rev:.*|^(ns:[0-9]+(\/.*)?)/", $path) === 1) {
529
            return $path;
530
        }
531
532
        $path = trim($path, '/');
533
534
        return ($path === '') ? '' : '/'.$path;
535
    }
536
537
    /**
538
     * @param string $endpoint
539
     * @param array $arguments
540
     * @param string|resource|StreamInterface $body
541
     *
542
     * @return \Psr\Http\Message\ResponseInterface
543
     *
544
     * @throws \Exception
545
     */
546
    public function contentEndpointRequest(string $endpoint, array $arguments, $body = ''): ResponseInterface
547
    {
548
        $headers = ['Dropbox-API-Arg' => json_encode($arguments)];
549
550
        if ($body !== '') {
551
            $headers['Content-Type'] = 'application/octet-stream';
552
        }
553
554
        try {
555
            $response = $this->client->post("https://content.dropboxapi.com/2/{$endpoint}", [
556
                'headers' => $this->getHeaders($headers),
557
                'body' => $body,
558
            ]);
559
        } catch (ClientException $exception) {
560
            throw $this->determineException($exception);
561
        }
562
563
        return $response;
564
    }
565
566
    public function rpcEndpointRequest(string $endpoint, array $parameters = null): array
567
    {
568
        try {
569
            $options = ['headers' => $this->getHeaders()];
570
571
            if ($parameters) {
572
                $options['json'] = $parameters;
573
            }
574
575
            $response = $this->client->post("https://api.dropboxapi.com/2/{$endpoint}", $options);
576
        } catch (ClientException $exception) {
577
            throw $this->determineException($exception);
578
        }
579
580
        $response = json_decode($response->getBody(), true);
581
582
        return $response ?? [];
583
    }
584
585
    protected function determineException(ClientException $exception): Exception
586
    {
587
        if (in_array($exception->getResponse()->getStatusCode(), [400, 409])) {
588
            return new BadRequest($exception->getResponse());
0 ignored issues
show
Bug introduced by
It seems like $exception->getResponse() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
589
        }
590
591
        return $exception;
592
    }
593
594
    /**
595
     * @param $contents
596
     *
597
     * @return \GuzzleHttp\Psr7\PumpStream|\GuzzleHttp\Psr7\Stream
598
     */
599
    protected function getStream($contents)
600
    {
601
        if ($this->isPipe($contents)) {
602
            /* @var resource $contents */
603
            return new PumpStream(function ($length) use ($contents) {
604
                $data = fread($contents, $length);
605
                if (strlen($data) === 0) {
606
                    return false;
607
                }
608
609
                return $data;
610
            });
611
        }
612
613
        return Psr7\stream_for($contents);
614
    }
615
616
    /**
617
     * Get the access token.
618
     */
619
    public function getAccessToken(): string
620
    {
621
        return $this->accessToken;
622
    }
623
624
    /**
625
     * Set the access token.
626
     */
627
    public function setAccessToken(string $accessToken): self
628
    {
629
        $this->accessToken = $accessToken;
630
631
        return $this;
632
    }
633
634
    /**
635
     * Get the HTTP headers.
636
     */
637
    protected function getHeaders(array $headers = []): array
638
    {
639
        return array_merge([
640
            'Authorization' => "Bearer {$this->accessToken}",
641
        ], $headers);
642
    }
643
}
644