OAuth2Client::debugToken()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 18
ccs 14
cts 14
cp 1
crap 2
rs 9.6666
c 0
b 0
f 0
1
<?php
2
/**
3
 * Copyright 2017 Facebook, Inc.
4
 *
5
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
6
 * use, copy, modify, and distribute this software in source code or binary
7
 * form for use in connection with the web services and APIs provided by
8
 * Facebook.
9
 *
10
 * As with any software that integrates with the Facebook platform, your use
11
 * of this software is subject to the Facebook Developer Principles and
12
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
13
 * shall be included in all copies or substantial portions of the software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 * DEALINGS IN THE SOFTWARE.
22
 */
23
namespace Facebook\Authentication;
24
25
use Facebook\Facebook;
26
use Facebook\Application;
27
use Facebook\Request;
28
use Facebook\Response;
29
use Facebook\Client;
30
use Facebook\Exception\ResponseException;
31
use Facebook\Exception\SDKException;
32
33
/**
34
 * @package Facebook
35
 */
36
class OAuth2Client
37
{
38
    /**
39
     * @const string The base authorization URL.
40
     */
41
    const BASE_AUTHORIZATION_URL = 'https://www.facebook.com';
42
43
    /**
44
     * The Application entity.
45
     *
46
     * @var Application
47
     */
48
    protected $app;
49
50
    /**
51
     * The Facebook client.
52
     *
53
     * @var Client
54
     */
55
    protected $client;
56
57
    /**
58
     * The version of the Graph API to use.
59
     *
60
     * @var string
61
     */
62
    protected $graphVersion;
63
64
    /**
65
     * The last request sent to Graph.
66
     *
67
     * @var null|Request
68
     */
69
    protected $lastRequest;
70
71
    /**
72
     * @param Application $app
73
     * @param Client      $client
74
     * @param string      $graphVersion the version of the Graph API to use
75
     */
76 18
    public function __construct(Application $app, Client $client, $graphVersion)
77
    {
78 18
        $this->app = $app;
79 18
        $this->client = $client;
80 18
        $this->graphVersion = $graphVersion;
81 18
    }
82
83
    /**
84
     * Returns the last Request that was sent.
85
     * Useful for debugging and testing.
86
     *
87
     * @return null|Request
88
     */
89 4
    public function getLastRequest()
90
    {
91 4
        return $this->lastRequest;
92
    }
93
94
    /**
95
     * Get the metadata associated with the access token.
96
     *
97
     * @param AccessToken|string $accessToken the access token to debug
98
     *
99
     * @return AccessTokenMetadata
100
     */
101 1
    public function debugToken($accessToken)
102
    {
103 1
        $accessToken = $accessToken instanceof AccessToken ? $accessToken->getValue() : $accessToken;
104 1
        $params = ['input_token' => $accessToken];
105
106 1
        $this->lastRequest = new Request(
107 1
            $this->app,
108 1
            $this->app->getAccessToken(),
109 1
            'GET',
110 1
            '/debug_token',
111 1
            $params,
112 1
            null,
113 1
            $this->graphVersion
114
        );
115 1
        $response = $this->client->sendRequest($this->lastRequest);
116 1
        $metadata = $response->getDecodedBody();
117
118 1
        return new AccessTokenMetadata($metadata);
119
    }
120
121
    /**
122
     * Generates an authorization URL to begin the process of authenticating a user.
123
     *
124
     * @param string $redirectUrl the callback URL to redirect to
125
     * @param string $state       the CSPRNG-generated CSRF value
126
     * @param array  $scope       an array of permissions to request
127
     * @param array  $params      an array of parameters to generate URL
128
     * @param string $separator   the separator to use in http_build_query()
129
     *
130
     * @return string
131
     */
132 2
    public function getAuthorizationUrl($redirectUrl, $state, array $scope = [], array $params = [], $separator = '&')
133
    {
134
        $params += [
135 2
            'client_id' => $this->app->getId(),
136 2
            'state' => $state,
137 2
            'response_type' => 'code',
138
            'sdk' => 'php-sdk-' . Facebook::VERSION,
139 2
            'redirect_uri' => $redirectUrl,
140 2
            'scope' => implode(',', $scope)
141
        ];
142
143 2
        return static::BASE_AUTHORIZATION_URL . '/' . $this->graphVersion . '/dialog/oauth?' . http_build_query($params, null, $separator);
144
    }
145
146
    /**
147
     * Get a valid access token from a code.
148
     *
149
     * @param string $code
150
     * @param string $redirectUri
151
     *
152
     * @throws SDKException
153
     *
154
     * @return AccessToken
155
     */
156 2
    public function getAccessTokenFromCode($code, $redirectUri = '')
157
    {
158
        $params = [
159 2
            'code' => $code,
160 2
            'redirect_uri' => $redirectUri,
161
        ];
162
163 2
        return $this->requestAnAccessToken($params);
164
    }
165
166
    /**
167
     * Exchanges a short-lived access token with a long-lived access token.
168
     *
169
     * @param AccessToken|string $accessToken
170
     *
171
     * @throws SDKException
172
     *
173
     * @return AccessToken
174
     */
175 1
    public function getLongLivedAccessToken($accessToken)
176
    {
177 1
        $accessToken = $accessToken instanceof AccessToken ? $accessToken->getValue() : $accessToken;
178
        $params = [
179 1
            'grant_type' => 'fb_exchange_token',
180 1
            'fb_exchange_token' => $accessToken,
181
        ];
182
183 1
        return $this->requestAnAccessToken($params);
184
    }
185
186
    /**
187
     * Get a valid code from an access token.
188
     *
189
     * @param AccessToken|string $accessToken
190
     * @param string             $redirectUri
191
     *
192
     * @throws SDKException
193
     *
194
     * @return AccessToken
195
     */
196 1
    public function getCodeFromLongLivedAccessToken($accessToken, $redirectUri = '')
197
    {
198
        $params = [
199 1
            'redirect_uri' => $redirectUri,
200
        ];
201
202 1
        $response = $this->sendRequestWithClientParams('/oauth/client_code', $params, $accessToken);
203 1
        $data = $response->getDecodedBody();
204
205 1
        if (!isset($data['code'])) {
206
            throw new SDKException('Code was not returned from Graph.', 401);
207
        }
208
209 1
        return $data['code'];
210
    }
211
212
    /**
213
     * Send a request to the OAuth endpoint.
214
     *
215
     * @param array $params
216
     *
217
     * @throws SDKException
218
     *
219
     * @return AccessToken
220
     */
221 3
    protected function requestAnAccessToken(array $params)
222
    {
223 3
        $response = $this->sendRequestWithClientParams('/oauth/access_token', $params);
224 3
        $data = $response->getDecodedBody();
225
226 3
        if (!isset($data['access_token'])) {
227
            throw new SDKException('Access token was not returned from Graph.', 401);
228
        }
229
230
        // Graph returns two different key names for expiration time
231
        // on the same endpoint. Doh! :/
232 3
        $expiresAt = 0;
233 3
        if (isset($data['expires'])) {
234
            // For exchanging a short lived token with a long lived token.
235
            // The expiration time in seconds will be returned as "expires".
236 2
            $expiresAt = time() + $data['expires'];
237 1
        } elseif (isset($data['expires_in'])) {
238
            // For exchanging a code for a short lived access token.
239
            // The expiration time in seconds will be returned as "expires_in".
240
            // See: https://developers.facebook.com/docs/facebook-login/access-tokens#long-via-code
241
            $expiresAt = time() + $data['expires_in'];
242
        }
243
244 3
        return new AccessToken($data['access_token'], $expiresAt);
245
    }
246
247
    /**
248
     * Send a request to Graph with an app access token.
249
     *
250
     * @param string                  $endpoint
251
     * @param array                   $params
252
     * @param null|AccessToken|string $accessToken
253
     *
254
     * @throws ResponseException
255
     *
256
     * @return Response
257
     */
258 4
    protected function sendRequestWithClientParams($endpoint, array $params, $accessToken = null)
259
    {
260 4
        $params += $this->getClientParams();
261
262 4
        $accessToken = $accessToken ?: $this->app->getAccessToken();
263
264 4
        $this->lastRequest = new Request(
265 4
            $this->app,
266 4
            $accessToken,
267 4
            'GET',
268 4
            $endpoint,
269 4
            $params,
270 4
            null,
271 4
            $this->graphVersion
272
        );
273
274 4
        return $this->client->sendRequest($this->lastRequest);
275
    }
276
277
    /**
278
     * Returns the client_* params for OAuth requests.
279
     *
280
     * @return array
281
     */
282 4
    protected function getClientParams()
283
    {
284
        return [
285 4
            'client_id' => $this->app->getId(),
286 4
            'client_secret' => $this->app->getSecret(),
287
        ];
288
    }
289
}
290