Completed
Pull Request — master (#42)
by Chad
02:53
created

Authentication::getRefreshTokenRequest()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
c 0
b 0
f 0
rs 8.9713
cc 1
eloc 16
nc 1
nop 5
1
<?php
2
namespace TraderInteractive\Api;
3
4
use DominionEnterprises\Util;
5
use DominionEnterprises\Util\Arrays;
6
use DominionEnterprises\Util\Http;
7
8
/**
9
 * Layer for OAuth2 Authentication
10
 */
11
final class Authentication
12
{
13
    /**
14
     * Function to create a Request object for obtaining a new token from the API
15
     *
16
     * @var callable
17
     */
18
    private $getTokenRequestFunc;
19
20
    /**
21
     * Private constructor to safeguard undeclared functions
22
     *
23
     * @param callable $getTokenRequestFunc Function to create a Request object for obtaining a new token from the API
24
     */
25
    private function __construct(callable $getTokenRequestFunc)
26
    {
27
        $this->getTokenRequestFunc = $getTokenRequestFunc;
28
    }
29
30
    /**
31
     * Creates a new instance of Authentication for Client Credentials grant type
32
     *
33
     * @param string $clientId The oauth client id
34
     * @param string $clientSecret The oauth client secret
35
     * @param string $refreshResource The refresh token resource of the API
36
     *     Only needed since apigee doesnt use the token resource that is in the oauth2 spec
37
     *
38
     * @return \DominionEnterprises\Api\Authentication
39
     */
40
    public static function createClientCredentials(
41
        $clientId,
42
        $clientSecret,
43
        $refreshResource = 'token',
44
        $tokenResource = 'token'
45
    ) {
46
        Util::throwIfNotType(['string' => [$clientId, $clientSecret]], true);
47
48
        $getTokenRequestFunc = function (
49
            $baseUrl,
50
            $refreshToken
51
        ) use (
52
            $clientId,
53
            $clientSecret,
54
            $refreshResource,
55
            $tokenResource
56
        ) {
57
            if ($refreshToken !== null) {
58
                return self::getRefreshTokenRequest(
59
                    $baseUrl,
60
                    $clientId,
61
                    $clientSecret,
62
                    $refreshResource,
63
                    $refreshToken
64
                );
65
            }
66
67
            $data = ['client_id' => $clientId, 'client_secret' => $clientSecret, 'grant_type' => 'client_credentials'];
68
            return new Request(
69
                "{$baseUrl}/{$tokenResource}",
70
                'POST',
71
                Http::buildQueryString($data),
72
                ['Content-Type' => 'application/x-www-form-urlencoded']
73
            );
74
        };
75
76
        return new self($getTokenRequestFunc);
77
    }
78
79
    /**
80
     * Creates a new instance of Authentication for Owner Credentials grant type
81
     *
82
     * @param string $clientId The oauth client id
83
     * @param string $clientSecret The oauth client secret
84
     * @param string $username The oauth username
85
     * @param string $password The oauth password
86
     * @param string $refreshResource The refresh token resource of the API
87
     *     Only needed since apigee doesnt use the token resource that is in the oauth2 spec
88
     *
89
     * @return \DominionEnterprises\Api\Authentication
90
     */
91
    public static function createOwnerCredentials(
92
        $clientId,
93
        $clientSecret,
94
        $username,
95
        $password,
96
        $refreshResource = 'token',
97
        $tokenResource = 'token'
98
    ) {
99
        Util::throwIfNotType(['string' => [$clientId, $clientSecret, $username, $password]], true);
100
101
        $getTokenRequestFunc = function (
102
            $baseUrl,
103
            $refreshToken
104
        ) use (
105
            $clientId,
106
            $clientSecret,
107
            $username,
108
            $password,
109
            $refreshResource,
110
            $tokenResource
111
        ) {
112
            if ($refreshToken !== null) {
113
                return self::getRefreshTokenRequest(
114
                    $baseUrl,
115
                    $clientId,
116
                    $clientSecret,
117
                    $refreshResource,
118
                    $refreshToken
119
                );
120
            }
121
122
            $data = [
123
                'client_id' => $clientId,
124
                'client_secret' => $clientSecret,
125
                'username' => $username,
126
                'password' => $password,
127
                'grant_type' => 'password',
128
            ];
129
            return new Request(
130
                "{$baseUrl}/{$tokenResource}",
131
                'POST',
132
                Http::buildQueryString($data),
133
                ['Content-Type' => 'application/x-www-form-urlencoded']
134
            );
135
        };
136
137
        return new self($getTokenRequestFunc);
138
    }
139
140
    /**
141
     * Extracts an access token from the given API response
142
     *
143
     * @param \DominionEnterprises\Api\Response $response The API response containing the access token
144
     *
145
     * @return array Array containing the access token, refresh token and expires timestamp
146
     */
147
    public static function parseTokenResponse(Response $response)
148
    {
149
        $parsedJson = $response->getResponse();
150
        Util::ensureNot('invalid_client', Arrays::get($parsedJson, 'error'), 'Invalid Credentials');
151
        Util::ensure(200, $response->getHttpCode(), Arrays::get($parsedJson, 'error_description', 'Unknown API error'));
152
        return [
153
            $parsedJson['access_token'],
154
            Arrays::get($parsedJson, 'refresh_token'),
155
            time() + (int)$parsedJson['expires_in'],
156
        ];
157
    }
158
159
    /**
160
     * Creates a Request object for obtaining a new token from the API
161
     *
162
     * @param string $baseUrl The base url of the API
163
     * @param string $refreshToken The refresh token of the API
164
     *
165
     * @return \DominionEnterprises\Api\Request
166
     */
167
    public function getTokenRequest($baseUrl, $refreshToken)
168
    {
169
        Util::throwIfNotType(['string' => [$baseUrl]], true);
170
        Util::throwIfNotType(['string' => [$refreshToken]], true, true);
171
172
        return call_user_func($this->getTokenRequestFunc, $baseUrl, $refreshToken);
173
    }
174
175
    /**
176
     * Build a refresh token request
177
     *
178
     * @param string $baseUrl API base url
179
     * @param string $clientId The client id
180
     * @param string $clientSecret The client secret
181
     * @param string $refreshResource The refresh token resource of the API
182
     *     Only needed since apigee doesnt use the token resource that is in the oauth2 spec
183
     * @param string $refreshToken The refresh token of the API
184
     *
185
     * @return \DominionEnterprises\Api\Request The built token refresh request
186
     */
187
    private static function getRefreshTokenRequest(
188
        $baseUrl,
189
        $clientId,
190
        $clientSecret,
191
        $refreshResource,
192
        $refreshToken
193
    ) {
194
        //NOTE client_id and client_secret are needed for Apigee but are not in the oauth2 spec
195
        $data = [
196
            'client_id' => $clientId,
197
            'client_secret' => $clientSecret,
198
            'refresh_token' => $refreshToken,
199
            'grant_type' => 'refresh_token',
200
        ];
201
202
        //NOTE the oauth2 spec says the refresh resource should be the same as the token resource, which is impossible
203
        //in Apigee and why the $refreshResource variable exists
204
        return new Request(
205
            "{$baseUrl}/{$refreshResource}",
206
            'POST',
207
            Http::buildQueryString($data),
208
            ['Content-Type' => 'application/x-www-form-urlencoded']
209
        );
210
    }
211
}
212