From 9b6c7a79b354dabf18cacfb9f38603bae1d3a909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Lam=C3=A9?= Date: Fri, 24 Nov 2023 14:45:11 +0100 Subject: [PATCH 1/7] Add refreshToken method --- src/Two/AbstractProvider.php | 27 +++++++++++ src/Two/Token.php | 86 ++++++++++++++++++++++++++++++++++++ tests/OAuthTwoTest.php | 20 +++++++++ 3 files changed, 133 insertions(+) create mode 100644 src/Two/Token.php diff --git a/src/Two/AbstractProvider.php b/src/Two/AbstractProvider.php index 236b75fa..ff56c291 100644 --- a/src/Two/AbstractProvider.php +++ b/src/Two/AbstractProvider.php @@ -340,6 +340,33 @@ protected function getTokenFields($code) return $fields; } + /** + * Refresh a user access token with a refresh token. + * + * @param string $refreshToken + * @return Token + */ + public function refreshToken($refreshToken) + { + $response = $this->getHttpClient()->post($this->getTokenUrl(), [ + RequestOptions::HEADERS => ['Accept' => 'application/json'], + RequestOptions::FORM_PARAMS => [ + 'grant_type' => 'refresh_token', + 'refresh_token' => $refreshToken, + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + ] + ]); + + $response = json_decode($response->getBody(), true); + + return (new Token) + ->setToken(Arr::get($response, 'access_token')) + ->setRefreshToken(Arr::get($response, 'refresh_token')) + ->setExpiresIn(Arr::get($response, 'expires_in')) + ->setApprovedScopes(explode($this->scopeSeparator, Arr::get($response, 'scope', ''))); + } + /** * Get the code from the request. * diff --git a/src/Two/Token.php b/src/Two/Token.php new file mode 100644 index 00000000..34bcccdf --- /dev/null +++ b/src/Two/Token.php @@ -0,0 +1,86 @@ +token = $token; + + return $this; + } + + /** + * Set the refresh token required to obtain a new access token. + * + * @param string $refreshToken + * @return $this + */ + public function setRefreshToken($refreshToken) + { + $this->refreshToken = $refreshToken; + + return $this; + } + + /** + * Set the number of seconds the access token is valid for. + * + * @param int $expiresIn + * @return $this + */ + public function setExpiresIn($expiresIn) + { + $this->expiresIn = $expiresIn; + + return $this; + } + + /** + * Set the scopes that were approved by the user during authentication. + * + * @param array $approvedScopes + * @return $this + */ + public function setApprovedScopes($approvedScopes) + { + $this->approvedScopes = $approvedScopes; + + return $this; + } +} diff --git a/tests/OAuthTwoTest.php b/tests/OAuthTwoTest.php index 972a2a4d..288dc882 100644 --- a/tests/OAuthTwoTest.php +++ b/tests/OAuthTwoTest.php @@ -10,6 +10,7 @@ use Laravel\Socialite\Tests\Fixtures\OAuthTwoTestProviderStub; use Laravel\Socialite\Tests\Fixtures\OAuthTwoWithPKCETestProviderStub; use Laravel\Socialite\Two\InvalidStateException; +use Laravel\Socialite\Two\Token; use Laravel\Socialite\Two\User; use Mockery as m; use PHPUnit\Framework\TestCase; @@ -178,4 +179,23 @@ public function testExceptionIsThrownIfStateIsNotSet() $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect'); $provider->user(); } + + public function testUserRefreshesToken() + { + $request = Request::create('/'); + $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect_uri'); + $provider->http = m::mock(stdClass::class); + $provider->http->expects('post')->with('http://token.url', [ + 'headers' => ['Accept' => 'application/json'], + 'form_params' => ['grant_type' => 'refresh_token', 'client_id' => 'client_id', 'client_secret' => 'client_secret', 'refresh_token' => 'refresh_token'], + ])->andReturns($response = m::mock(stdClass::class)); + $response->expects('getBody')->andReturns('{ "access_token" : "access_token", "refresh_token" : "refresh_token", "expires_in" : 3600, "scope" : "scope1,scope2" }'); + $tokenResponse = $provider->refreshToken('refresh_token'); + + $this->assertInstanceOf(Token::class, $tokenResponse); + $this->assertSame('access_token', $tokenResponse->token); + $this->assertSame('refresh_token', $tokenResponse->refreshToken); + $this->assertSame(3600, $tokenResponse->expiresIn); + $this->assertSame(['scope1', 'scope2'], $tokenResponse->approvedScopes); + } } From 55864420b3ab7cc44558521abe74e6ededebdc63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Lam=C3=A9?= Date: Fri, 24 Nov 2023 15:23:43 +0100 Subject: [PATCH 2/7] Fix code style --- src/Two/AbstractProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Two/AbstractProvider.php b/src/Two/AbstractProvider.php index ff56c291..4f4f8623 100644 --- a/src/Two/AbstractProvider.php +++ b/src/Two/AbstractProvider.php @@ -355,7 +355,7 @@ public function refreshToken($refreshToken) 'refresh_token' => $refreshToken, 'client_id' => $this->clientId, 'client_secret' => $this->clientSecret, - ] + ], ]); $response = json_decode($response->getBody(), true); From d34d334d356f806be3f6c4a21aa58956f7c637f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Lam=C3=A9?= Date: Fri, 24 Nov 2023 15:30:03 +0100 Subject: [PATCH 3/7] Fix naming --- tests/OAuthTwoTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/OAuthTwoTest.php b/tests/OAuthTwoTest.php index 288dc882..5c931c94 100644 --- a/tests/OAuthTwoTest.php +++ b/tests/OAuthTwoTest.php @@ -190,12 +190,12 @@ public function testUserRefreshesToken() 'form_params' => ['grant_type' => 'refresh_token', 'client_id' => 'client_id', 'client_secret' => 'client_secret', 'refresh_token' => 'refresh_token'], ])->andReturns($response = m::mock(stdClass::class)); $response->expects('getBody')->andReturns('{ "access_token" : "access_token", "refresh_token" : "refresh_token", "expires_in" : 3600, "scope" : "scope1,scope2" }'); - $tokenResponse = $provider->refreshToken('refresh_token'); + $token = $provider->refreshToken('refresh_token'); - $this->assertInstanceOf(Token::class, $tokenResponse); - $this->assertSame('access_token', $tokenResponse->token); - $this->assertSame('refresh_token', $tokenResponse->refreshToken); - $this->assertSame(3600, $tokenResponse->expiresIn); - $this->assertSame(['scope1', 'scope2'], $tokenResponse->approvedScopes); + $this->assertInstanceOf(Token::class, $token); + $this->assertSame('access_token', $token->token); + $this->assertSame('refresh_token', $token->refreshToken); + $this->assertSame(3600, $token->expiresIn); + $this->assertSame(['scope1', 'scope2'], $token->approvedScopes); } } From 85ab056504f01fb2cf60d896c07ad5cc76c8db3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Lam=C3=A9?= Date: Fri, 1 Dec 2023 18:02:43 +0100 Subject: [PATCH 4/7] Fix Twitter provider --- src/Two/AbstractProvider.php | 25 ++++++++++++++++++------- src/Two/TwitterProvider.php | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/Two/AbstractProvider.php b/src/Two/AbstractProvider.php index 4f4f8623..581f7270 100644 --- a/src/Two/AbstractProvider.php +++ b/src/Two/AbstractProvider.php @@ -347,6 +347,23 @@ protected function getTokenFields($code) * @return Token */ public function refreshToken($refreshToken) + { + $response = $this->getRefreshTokenResponse($refreshToken); + + return (new Token) + ->setToken(Arr::get($response, 'access_token')) + ->setRefreshToken(Arr::get($response, 'refresh_token')) + ->setExpiresIn(Arr::get($response, 'expires_in')) + ->setApprovedScopes(explode($this->scopeSeparator, Arr::get($response, 'scope', ''))); + } + + /** + * Get the refresh token response for the given refresh token. + * + * @param string $refreshToken + * @return array + */ + public function getRefreshTokenResponse($refreshToken) { $response = $this->getHttpClient()->post($this->getTokenUrl(), [ RequestOptions::HEADERS => ['Accept' => 'application/json'], @@ -358,13 +375,7 @@ public function refreshToken($refreshToken) ], ]); - $response = json_decode($response->getBody(), true); - - return (new Token) - ->setToken(Arr::get($response, 'access_token')) - ->setRefreshToken(Arr::get($response, 'refresh_token')) - ->setExpiresIn(Arr::get($response, 'expires_in')) - ->setApprovedScopes(explode($this->scopeSeparator, Arr::get($response, 'scope', ''))); + return json_decode($response->getBody(), true); } /** diff --git a/src/Two/TwitterProvider.php b/src/Two/TwitterProvider.php index b6661f71..05adc36d 100644 --- a/src/Two/TwitterProvider.php +++ b/src/Two/TwitterProvider.php @@ -91,6 +91,25 @@ public function getAccessTokenResponse($code) return json_decode($response->getBody(), true); } + /** + * {@inheritdoc} + */ + public function getRefreshTokenResponse($refreshToken) + { + $response = $this->getHttpClient()->post($this->getTokenUrl(), [ + RequestOptions::HEADERS => ['Accept' => 'application/json'], + RequestOptions::AUTH => [$this->clientId, $this->clientSecret], + RequestOptions::FORM_PARAMS => [ + 'grant_type' => 'refresh_token', + 'refresh_token' => $refreshToken, + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + ], + ]); + + return json_decode($response->getBody(), true); + } + /** * {@inheritdoc} */ From 37c1f867ed6c01f3d8f5bfce62a4d098f43b934a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Lam=C3=A9?= Date: Fri, 1 Dec 2023 18:07:01 +0100 Subject: [PATCH 5/7] Remove unnecessary parameter from Twitter provider --- src/Two/TwitterProvider.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Two/TwitterProvider.php b/src/Two/TwitterProvider.php index 05adc36d..b5824dab 100644 --- a/src/Two/TwitterProvider.php +++ b/src/Two/TwitterProvider.php @@ -103,7 +103,6 @@ public function getRefreshTokenResponse($refreshToken) 'grant_type' => 'refresh_token', 'refresh_token' => $refreshToken, 'client_id' => $this->clientId, - 'client_secret' => $this->clientSecret, ], ]); From 96957d026e38ae97f74a12c5f8bda74aea920431 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 1 Dec 2023 16:17:29 -0600 Subject: [PATCH 6/7] formatting --- src/Two/AbstractProvider.php | 23 +++++++++--------- src/Two/Token.php | 46 ++++-------------------------------- src/Two/TwitterProvider.php | 2 +- 3 files changed, 17 insertions(+), 54 deletions(-) diff --git a/src/Two/AbstractProvider.php b/src/Two/AbstractProvider.php index 581f7270..3a56eda2 100644 --- a/src/Two/AbstractProvider.php +++ b/src/Two/AbstractProvider.php @@ -341,20 +341,21 @@ protected function getTokenFields($code) } /** - * Refresh a user access token with a refresh token. + * Refresh a user's access token with a refresh token. * * @param string $refreshToken - * @return Token + * @return \Laravel\Socialite\Two\Token */ public function refreshToken($refreshToken) { $response = $this->getRefreshTokenResponse($refreshToken); - return (new Token) - ->setToken(Arr::get($response, 'access_token')) - ->setRefreshToken(Arr::get($response, 'refresh_token')) - ->setExpiresIn(Arr::get($response, 'expires_in')) - ->setApprovedScopes(explode($this->scopeSeparator, Arr::get($response, 'scope', ''))); + return new Token( + Arr::get($response, 'access_token'), + Arr::get($response, 'refresh_token'), + Arr::get($response, 'expires_in'), + explode($this->scopeSeparator, Arr::get($response, 'scope', '')), + ); } /** @@ -363,9 +364,9 @@ public function refreshToken($refreshToken) * @param string $refreshToken * @return array */ - public function getRefreshTokenResponse($refreshToken) + protected function getRefreshTokenResponse($refreshToken) { - $response = $this->getHttpClient()->post($this->getTokenUrl(), [ + return json_decode($this->getHttpClient()->post($this->getTokenUrl(), [ RequestOptions::HEADERS => ['Accept' => 'application/json'], RequestOptions::FORM_PARAMS => [ 'grant_type' => 'refresh_token', @@ -373,9 +374,7 @@ public function getRefreshTokenResponse($refreshToken) 'client_id' => $this->clientId, 'client_secret' => $this->clientSecret, ], - ]); - - return json_decode($response->getBody(), true); + ])->getBody(), true); } /** diff --git a/src/Two/Token.php b/src/Two/Token.php index 34bcccdf..c6af8447 100644 --- a/src/Two/Token.php +++ b/src/Two/Token.php @@ -33,54 +33,18 @@ class Token public $approvedScopes; /** - * Set the token on the user. + * Create a new token instance. * * @param string $token - * @return $this - */ - public function setToken($token) - { - $this->token = $token; - - return $this; - } - - /** - * Set the refresh token required to obtain a new access token. - * * @param string $refreshToken - * @return $this - */ - public function setRefreshToken($refreshToken) - { - $this->refreshToken = $refreshToken; - - return $this; - } - - /** - * Set the number of seconds the access token is valid for. - * * @param int $expiresIn - * @return $this - */ - public function setExpiresIn($expiresIn) - { - $this->expiresIn = $expiresIn; - - return $this; - } - - /** - * Set the scopes that were approved by the user during authentication. - * * @param array $approvedScopes - * @return $this */ - public function setApprovedScopes($approvedScopes) + public function __construct(string $token, string $refreshToken, int $expiresIn, array $approvedScopes) { + $this->token = $token; + $this->refreshToken = $refreshToken; + $this->expiresIn = $expiresIn; $this->approvedScopes = $approvedScopes; - - return $this; } } diff --git a/src/Two/TwitterProvider.php b/src/Two/TwitterProvider.php index b5824dab..98105918 100644 --- a/src/Two/TwitterProvider.php +++ b/src/Two/TwitterProvider.php @@ -94,7 +94,7 @@ public function getAccessTokenResponse($code) /** * {@inheritdoc} */ - public function getRefreshTokenResponse($refreshToken) + protected function getRefreshTokenResponse($refreshToken) { $response = $this->getHttpClient()->post($this->getTokenUrl(), [ RequestOptions::HEADERS => ['Accept' => 'application/json'], From 0ae1d798d8aebd2584299bd96f00a1316ca91247 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 1 Dec 2023 16:19:09 -0600 Subject: [PATCH 7/7] fix comma --- src/Two/AbstractProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Two/AbstractProvider.php b/src/Two/AbstractProvider.php index 3a56eda2..e70d4c29 100644 --- a/src/Two/AbstractProvider.php +++ b/src/Two/AbstractProvider.php @@ -354,7 +354,7 @@ public function refreshToken($refreshToken) Arr::get($response, 'access_token'), Arr::get($response, 'refresh_token'), Arr::get($response, 'expires_in'), - explode($this->scopeSeparator, Arr::get($response, 'scope', '')), + explode($this->scopeSeparator, Arr::get($response, 'scope', '')) ); }