1010use Salient \Core \Facade \Cache ;
1111use Salient \Core \Facade \Console ;
1212use Salient \Curler \Curler ;
13- use Salient \Http \Message \Response ;
1413use Salient \Http \Server \Server ;
1514use Salient \Http \Server \ServerResponse ;
1615use Salient \Utility \Arr ;
2120use Throwable ;
2221use UnexpectedValueException ;
2322
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
2924{
3025 private ?Server $ Listener ;
3126 private AbstractProvider $ Provider ;
32- /** @var OAuth2Flow:: * */
33- private int $ Flow ;
27+ /** @var self::GRANT_ * */
28+ private string $ Flow ;
3429 private string $ TokenKey ;
3530
3631 /**
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
6934 */
7035 abstract protected function getListener (): ?Server ;
7136
7237 /**
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
10439 */
10540 abstract protected function getProvider (): AbstractProvider ;
10641
10742 /**
108- * Return the OAuth 2.0 flow to use
43+ * Get the client's OAuth 2.0 flow
10944 *
110- * @return OAuth2Flow:: *
45+ * @return OAuth2Client::GRANT_ *
11146 */
112- abstract protected function getFlow (): int ;
47+ abstract protected function getFlow (): string ;
11348
11449 /**
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
11651 * disable JWT signature validation and decoding
11752 *
11853 * Required for token signature validation. Check the provider's
@@ -124,9 +59,13 @@ abstract protected function getJsonWebKeySetUrl(): ?string;
12459 * Called when an access token is received from the OAuth 2.0 provider
12560 *
12661 * @param array<string,mixed>|null $idToken
127- * @param OAuth2GrantType:: * $grantType
62+ * @param OAuth2Client::GRANT_ * $grantType
12863 */
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 ;
13069
13170 public function __construct ()
13271 {
@@ -215,7 +154,7 @@ final protected function refreshAccessToken(): ?OAuth2AccessToken
215154 return $ refreshToken === null
216155 ? null
217156 : $ this ->requestAccessToken (
218- OAuth2GrantType:: REFRESH_TOKEN ,
157+ self :: GRANT_REFRESH_TOKEN ,
219158 ['refresh_token ' => $ refreshToken ]
220159 );
221160 }
@@ -251,14 +190,14 @@ final protected function authorize(array $options = []): OAuth2AccessToken
251190 $ this ->flushTokens ();
252191
253192 switch ($ this ->Flow ) {
254- case OAuth2Flow:: CLIENT_CREDENTIALS :
193+ case self :: GRANT_CLIENT_CREDENTIALS :
255194 return $ this ->authorizeWithClientCredentials ($ options );
256195
257- case OAuth2Flow:: AUTHORIZATION_CODE :
196+ case self :: GRANT_AUTHORIZATION_CODE :
258197 return $ this ->authorizeWithAuthorizationCode ($ options );
259198
260199 default :
261- throw new LogicException (sprintf ('Invalid OAuth2Flow : %d ' , $ this ->Flow ));
200+ throw new LogicException (sprintf ('Invalid flow : %s ' , $ this ->Flow ));
262201 }
263202 }
264203
@@ -282,7 +221,7 @@ private function authorizeWithClientCredentials(array $options = []): OAuth2Acce
282221 }
283222
284223 return $ this ->requestAccessToken (
285- OAuth2GrantType:: CLIENT_CREDENTIALS ,
224+ self :: GRANT_CLIENT_CREDENTIALS ,
286225 $ options
287226 );
288227 }
@@ -327,7 +266,7 @@ private function authorizeWithAuthorizationCode(array $options = []): OAuth2Acce
327266 }
328267
329268 return $ this ->requestAccessToken (
330- OAuth2GrantType:: AUTHORIZATION_CODE ,
269+ self :: GRANT_AUTHORIZATION_CODE ,
331270 ['code ' => $ code ],
332271 $ options ['scope ' ] ?? null
333272 );
@@ -372,7 +311,7 @@ private function receiveAuthorizationCode(ServerRequestInterface $request): Serv
372311 * Request an access token from the OAuth 2.0 provider, then validate, cache
373312 * and return it
374313 *
375- * @param string&OAuth2GrantType:: * $grantType
314+ * @param self::GRANT_ * $grantType
376315 * @param array<string,mixed> $options
377316 * @param mixed $scope
378317 */
@@ -418,7 +357,7 @@ private function requestAccessToken(
418357 ?? $ options ['scope ' ]
419358 ?? $ scope );
420359
421- if (!$ scopes && $ grantType === OAuth2GrantType:: REFRESH_TOKEN ) {
360+ if (!$ scopes && $ grantType === self :: GRANT_REFRESH_TOKEN ) {
422361 $ lastToken = Cache::getInstance ()->getInstanceOf ($ this ->TokenKey , OAuth2AccessToken::class);
423362 if ($ lastToken ) {
424363 $ scopes = $ lastToken ->getScopes ();
0 commit comments