10
10
use Salient \Core \Facade \Cache ;
11
11
use Salient \Core \Facade \Console ;
12
12
use Salient \Curler \Curler ;
13
- use Salient \Http \Message \Response ;
14
13
use Salient \Http \Server \Server ;
15
14
use Salient \Http \Server \ServerResponse ;
16
15
use Salient \Utility \Arr ;
21
20
use Throwable ;
22
21
use UnexpectedValueException ;
23
22
24
- /**
25
- * A headless OAuth 2.0 client that acquires and validates tokens required for
26
- * access to protected resources
27
- */
28
- abstract class OAuth2Client
23
+ abstract class OAuth2Client implements HasGrantType, HasResponseType
29
24
{
30
25
private ?Server $ Listener ;
31
26
private AbstractProvider $ Provider ;
32
- /** @var OAuth2Flow:: * */
33
- private int $ Flow ;
27
+ /** @var self::GRANT_ * */
28
+ private string $ Flow ;
34
29
private string $ TokenKey ;
35
30
36
31
/**
37
- * Return an HTTP listener to receive OAuth 2.0 redirects from the provider,
38
- * or null to disable flows that require it
39
- *
40
- * Reference implementation:
41
- *
42
- * ```php
43
- * <?php
44
- * class OAuth2TestClient extends OAuth2Client
45
- * {
46
- * protected function getListener(): ?Server
47
- * {
48
- * $listener = new Server(
49
- * Env::get('app_host', 'localhost'),
50
- * Env::getInt('app_port', 27755),
51
- * );
52
- *
53
- * $proxyHost = Env::getNullable('app_proxy_host', null);
54
- * $proxyPort = Env::getNullableInt('app_proxy_port', null);
55
- *
56
- * if ($proxyHost !== null && $proxyPort !== null) {
57
- * return $listener->withProxy(
58
- * $proxyHost,
59
- * $proxyPort,
60
- * Env::getNullableBool('app_proxy_tls', null),
61
- * Env::get('app_proxy_base_path', ''),
62
- * );
63
- * }
64
- *
65
- * return $listener;
66
- * }
67
- * }
68
- * ```
32
+ * Get an in-process HTTP server to receive OAuth 2.0 redirects from the
33
+ * provider to the client, or null if flows that require it are disabled
69
34
*/
70
35
abstract protected function getListener (): ?Server ;
71
36
72
37
/**
73
- * Return an OAuth 2.0 provider to request and validate tokens that
74
- * authorize access to the resource server
75
- *
76
- * Example:
77
- *
78
- * The following provider could be used to authorize access to the Microsoft
79
- * Graph API on behalf of a user or application. `redirectUri` can be
80
- * omitted if support for the Authorization Code flow is not required.
81
- *
82
- * > The only scope required for access to the Microsoft Graph API is
83
- * > `https://graph.microsoft.com/.default`
84
- *
85
- * ```php
86
- * <?php
87
- * class OAuth2TestClient extends OAuth2Client
88
- * {
89
- * protected function getProvider(): GenericProvider
90
- * {
91
- * return new GenericProvider([
92
- * 'clientId' => $this->AppId,
93
- * 'clientSecret' => $this->Secret,
94
- * 'redirectUri' => $this->getRedirectUri(),
95
- * 'urlAuthorize' => sprintf('https://login.microsoftonline.com/%s/oauth2/authorize', $this->TenantId),
96
- * 'urlAccessToken' => sprintf('https://login.microsoftonline.com/%s/oauth2/v2.0/token', $this->TenantId),
97
- * 'urlResourceOwnerDetails' => sprintf('https://login.microsoftonline.com/%s/openid/userinfo', $this->TenantId),
98
- * 'scopes' => ['openid', 'profile', 'email', 'offline_access', 'https://graph.microsoft.com/.default'],
99
- * 'scopeSeparator' => ' ',
100
- * ]);
101
- * }
102
- * }
103
- * ```
38
+ * Get an OAuth 2.0 provider for the client
104
39
*/
105
40
abstract protected function getProvider (): AbstractProvider ;
106
41
107
42
/**
108
- * Return the OAuth 2.0 flow to use
43
+ * Get the client's OAuth 2.0 flow
109
44
*
110
- * @return OAuth2Flow:: *
45
+ * @return OAuth2Client::GRANT_ *
111
46
*/
112
- abstract protected function getFlow (): int ;
47
+ abstract protected function getFlow (): string ;
113
48
114
49
/**
115
- * Return the URL of the OAuth 2.0 provider's JSON Web Key Set, or null to
50
+ * Get the URL of the OAuth 2.0 provider's JSON Web Key Set, or null to
116
51
* disable JWT signature validation and decoding
117
52
*
118
53
* Required for token signature validation. Check the provider's
@@ -124,9 +59,13 @@ abstract protected function getJsonWebKeySetUrl(): ?string;
124
59
* Called when an access token is received from the OAuth 2.0 provider
125
60
*
126
61
* @param array<string,mixed>|null $idToken
127
- * @param OAuth2GrantType:: * $grantType
62
+ * @param OAuth2Client::GRANT_ * $grantType
128
63
*/
129
- abstract protected function receiveToken (OAuth2AccessToken $ token , ?array $ idToken , string $ grantType ): void ;
64
+ abstract protected function receiveToken (
65
+ OAuth2AccessToken $ token ,
66
+ ?array $ idToken ,
67
+ string $ grantType
68
+ ): void ;
130
69
131
70
public function __construct ()
132
71
{
@@ -215,7 +154,7 @@ final protected function refreshAccessToken(): ?OAuth2AccessToken
215
154
return $ refreshToken === null
216
155
? null
217
156
: $ this ->requestAccessToken (
218
- OAuth2GrantType:: REFRESH_TOKEN ,
157
+ self :: GRANT_REFRESH_TOKEN ,
219
158
['refresh_token ' => $ refreshToken ]
220
159
);
221
160
}
@@ -251,14 +190,14 @@ final protected function authorize(array $options = []): OAuth2AccessToken
251
190
$ this ->flushTokens ();
252
191
253
192
switch ($ this ->Flow ) {
254
- case OAuth2Flow:: CLIENT_CREDENTIALS :
193
+ case self :: GRANT_CLIENT_CREDENTIALS :
255
194
return $ this ->authorizeWithClientCredentials ($ options );
256
195
257
- case OAuth2Flow:: AUTHORIZATION_CODE :
196
+ case self :: GRANT_AUTHORIZATION_CODE :
258
197
return $ this ->authorizeWithAuthorizationCode ($ options );
259
198
260
199
default :
261
- throw new LogicException (sprintf ('Invalid OAuth2Flow : %d ' , $ this ->Flow ));
200
+ throw new LogicException (sprintf ('Invalid flow : %s ' , $ this ->Flow ));
262
201
}
263
202
}
264
203
@@ -282,7 +221,7 @@ private function authorizeWithClientCredentials(array $options = []): OAuth2Acce
282
221
}
283
222
284
223
return $ this ->requestAccessToken (
285
- OAuth2GrantType:: CLIENT_CREDENTIALS ,
224
+ self :: GRANT_CLIENT_CREDENTIALS ,
286
225
$ options
287
226
);
288
227
}
@@ -327,7 +266,7 @@ private function authorizeWithAuthorizationCode(array $options = []): OAuth2Acce
327
266
}
328
267
329
268
return $ this ->requestAccessToken (
330
- OAuth2GrantType:: AUTHORIZATION_CODE ,
269
+ self :: GRANT_AUTHORIZATION_CODE ,
331
270
['code ' => $ code ],
332
271
$ options ['scope ' ] ?? null
333
272
);
@@ -372,7 +311,7 @@ private function receiveAuthorizationCode(ServerRequestInterface $request): Serv
372
311
* Request an access token from the OAuth 2.0 provider, then validate, cache
373
312
* and return it
374
313
*
375
- * @param string&OAuth2GrantType:: * $grantType
314
+ * @param self::GRANT_ * $grantType
376
315
* @param array<string,mixed> $options
377
316
* @param mixed $scope
378
317
*/
@@ -418,7 +357,7 @@ private function requestAccessToken(
418
357
?? $ options ['scope ' ]
419
358
?? $ scope );
420
359
421
- if (!$ scopes && $ grantType === OAuth2GrantType:: REFRESH_TOKEN ) {
360
+ if (!$ scopes && $ grantType === self :: GRANT_REFRESH_TOKEN ) {
422
361
$ lastToken = Cache::getInstance ()->getInstanceOf ($ this ->TokenKey , OAuth2AccessToken::class);
423
362
if ($ lastToken ) {
424
363
$ scopes = $ lastToken ->getScopes ();
0 commit comments