OAuth2Client   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 254
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 1
Bugs 1 Features 0
Metric Value
dl 0
loc 254
rs 10
c 1
b 1
f 0
wmc 18
lcom 1
cbo 7

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A getLastRequest() 0 4 1
A debugToken() 0 19 2
A getAuthorizationUrl() 0 13 1
A getAccessTokenFromCode() 0 9 1
A getLongLivedAccessToken() 0 10 2
A getCodeFromLongLivedAccessToken() 0 15 2
B requestAnAccessToken() 0 25 4
A sendRequestWithClientParams() 0 18 2
A getClientParams() 0 7 1
1
<?php
2
/**
3
 * Copyright 2016 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
 */
24
namespace Facebook\Authentication;
25
26
use Facebook\Facebook;
27
use Facebook\FacebookApp;
28
use Facebook\FacebookRequest;
29
use Facebook\FacebookResponse;
30
use Facebook\FacebookClient;
31
use Facebook\Exceptions\FacebookResponseException;
32
use Facebook\Exceptions\FacebookSDKException;
33
34
/**
35
 * Class OAuth2Client
36
 *
37
 * @package Facebook
38
 */
39
class OAuth2Client
40
{
41
    /**
42
     * @const string The base authorization URL.
43
     */
44
    const BASE_AUTHORIZATION_URL = 'https://www.facebook.com';
45
46
    /**
47
     * The FacebookApp entity.
48
     *
49
     * @var FacebookApp
50
     */
51
    protected $app;
52
53
    /**
54
     * The Facebook client.
55
     *
56
     * @var FacebookClient
57
     */
58
    protected $client;
59
60
    /**
61
     * The version of the Graph API to use.
62
     *
63
     * @var string
64
     */
65
    protected $graphVersion;
66
67
    /**
68
     * The last request sent to Graph.
69
     *
70
     * @var FacebookRequest|null
71
     */
72
    protected $lastRequest;
73
74
    /**
75
     * @param FacebookApp    $app
76
     * @param FacebookClient $client
77
     * @param string|null    $graphVersion The version of the Graph API to use.
78
     */
79
    public function __construct(FacebookApp $app, FacebookClient $client, $graphVersion = null)
80
    {
81
        $this->app = $app;
82
        $this->client = $client;
83
        $this->graphVersion = $graphVersion ?: Facebook::DEFAULT_GRAPH_VERSION;
84
    }
85
86
    /**
87
     * Returns the last FacebookRequest that was sent.
88
     * Useful for debugging and testing.
89
     *
90
     * @return FacebookRequest|null
91
     */
92
    public function getLastRequest()
93
    {
94
        return $this->lastRequest;
95
    }
96
97
    /**
98
     * Get the metadata associated with the access token.
99
     *
100
     * @param AccessToken|string $accessToken The access token to debug.
101
     *
102
     * @return AccessTokenMetadata
103
     */
104
    public function debugToken($accessToken)
105
    {
106
        $accessToken = $accessToken instanceof AccessToken ? $accessToken->getValue() : $accessToken;
107
        $params = ['input_token' => $accessToken];
108
109
        $this->lastRequest = new FacebookRequest(
110
            $this->app,
111
            $this->app->getAccessToken(),
112
            'GET',
113
            '/debug_token',
114
            $params,
115
            null,
116
            $this->graphVersion
117
        );
118
        $response = $this->client->sendRequest($this->lastRequest);
119
        $metadata = $response->getDecodedBody();
120
121
        return new AccessTokenMetadata($metadata);
122
    }
123
124
    /**
125
     * Generates an authorization URL to begin the process of authenticating a user.
126
     *
127
     * @param string $redirectUrl The callback URL to redirect to.
128
     * @param array  $scope       An array of permissions to request.
129
     * @param string $state       The CSPRNG-generated CSRF value.
130
     * @param array  $params      An array of parameters to generate URL.
131
     * @param string $separator   The separator to use in http_build_query().
132
     *
133
     * @return string
134
     */
135
    public function getAuthorizationUrl($redirectUrl, $state, array $scope = [], array $params = [], $separator = '&')
136
    {
137
        $params += [
138
            'client_id' => $this->app->getId(),
139
            'state' => $state,
140
            'response_type' => 'code',
141
            'sdk' => 'php-sdk-' . Facebook::VERSION,
142
            'redirect_uri' => $redirectUrl,
143
            'scope' => implode(',', $scope)
144
        ];
145
146
        return static::BASE_AUTHORIZATION_URL . '/' . $this->graphVersion . '/dialog/oauth?' . http_build_query($params, null, $separator);
147
    }
148
149
    /**
150
     * Get a valid access token from a code.
151
     *
152
     * @param string $code
153
     * @param string $redirectUri
154
     *
155
     * @return AccessToken
156
     *
157
     * @throws FacebookSDKException
158
     */
159
    public function getAccessTokenFromCode($code, $redirectUri = '')
160
    {
161
        $params = [
162
            'code' => $code,
163
            'redirect_uri' => $redirectUri,
164
        ];
165
166
        return $this->requestAnAccessToken($params);
167
    }
168
169
    /**
170
     * Exchanges a short-lived access token with a long-lived access token.
171
     *
172
     * @param AccessToken|string $accessToken
173
     *
174
     * @return AccessToken
175
     *
176
     * @throws FacebookSDKException
177
     */
178
    public function getLongLivedAccessToken($accessToken)
179
    {
180
        $accessToken = $accessToken instanceof AccessToken ? $accessToken->getValue() : $accessToken;
181
        $params = [
182
            'grant_type' => 'fb_exchange_token',
183
            'fb_exchange_token' => $accessToken,
184
        ];
185
186
        return $this->requestAnAccessToken($params);
187
    }
188
189
    /**
190
     * Get a valid code from an access token.
191
     *
192
     * @param AccessToken|string $accessToken
193
     * @param string             $redirectUri
194
     *
195
     * @return AccessToken
196
     *
197
     * @throws FacebookSDKException
198
     */
199
    public function getCodeFromLongLivedAccessToken($accessToken, $redirectUri = '')
200
    {
201
        $params = [
202
            'redirect_uri' => $redirectUri,
203
        ];
204
205
        $response = $this->sendRequestWithClientParams('/oauth/client_code', $params, $accessToken);
206
        $data = $response->getDecodedBody();
207
208
        if (!isset($data['code'])) {
209
            throw new FacebookSDKException('Code was not returned from Graph.', 401);
210
        }
211
212
        return $data['code'];
213
    }
214
215
    /**
216
     * Send a request to the OAuth endpoint.
217
     *
218
     * @param array $params
219
     *
220
     * @return AccessToken
221
     *
222
     * @throws FacebookSDKException
223
     */
224
    protected function requestAnAccessToken(array $params)
225
    {
226
        $response = $this->sendRequestWithClientParams('/oauth/access_token', $params);
227
        $data = $response->getDecodedBody();
228
229
        if (!isset($data['access_token'])) {
230
            throw new FacebookSDKException('Access token was not returned from Graph.', 401);
231
        }
232
233
        // Graph returns two different key names for expiration time
234
        // on the same endpoint. Doh! :/
235
        $expiresAt = 0;
236
        if (isset($data['expires'])) {
237
            // For exchanging a short lived token with a long lived token.
238
            // The expiration time in seconds will be returned as "expires".
239
            $expiresAt = time() + $data['expires'];
240
        } elseif (isset($data['expires_in'])) {
241
            // For exchanging a code for a short lived access token.
242
            // The expiration time in seconds will be returned as "expires_in".
243
            // See: https://developers.facebook.com/docs/facebook-login/access-tokens#long-via-code
244
            $expiresAt = time() + $data['expires_in'];
245
        }
246
247
        return new AccessToken($data['access_token'], $expiresAt);
248
    }
249
250
    /**
251
     * Send a request to Graph with an app access token.
252
     *
253
     * @param string                  $endpoint
254
     * @param array                   $params
255
     * @param AccessToken|string|null $accessToken
256
     *
257
     * @return FacebookResponse
258
     *
259
     * @throws FacebookResponseException
260
     */
261
    protected function sendRequestWithClientParams($endpoint, array $params, $accessToken = null)
262
    {
263
        $params += $this->getClientParams();
264
265
        $accessToken = $accessToken ?: $this->app->getAccessToken();
266
267
        $this->lastRequest = new FacebookRequest(
268
            $this->app,
269
            $accessToken,
270
            'GET',
271
            $endpoint,
272
            $params,
273
            null,
274
            $this->graphVersion
275
        );
276
277
        return $this->client->sendRequest($this->lastRequest);
278
    }
279
280
    /**
281
     * Returns the client_* params for OAuth requests.
282
     *
283
     * @return array
284
     */
285
    protected function getClientParams()
286
    {
287
        return [
288
            'client_id' => $this->app->getId(),
289
            'client_secret' => $this->app->getSecret(),
290
        ];
291
    }
292
}
293