diff --git a/src/Provider/Withings.php b/src/Provider/Withings.php index 0548607..bc36bbb 100644 --- a/src/Provider/Withings.php +++ b/src/Provider/Withings.php @@ -6,6 +6,7 @@ use League\OAuth2\Client\Provider\GenericResourceOwner; use League\OAuth2\Client\Provider\Exception\IdentityProviderException; use League\OAuth2\Client\Token\AccessToken; +use League\OAuth2\Client\Token\AccessTokenInterface; use League\OAuth2\Client\Tool\BearerAuthorizationTrait; use Psr\Http\Message\ResponseInterface; @@ -65,7 +66,25 @@ public function getBaseAuthorizationUrl() */ public function getBaseAccessTokenUrl(array $params) { - return static::BASE_WITHINGS_URL.'/oauth2/token'; + return static::BASE_WITHINGS_API_URL.'/v2/oauth2'; + } + + /** + * Requests an access token using a specified grant and option set. + * + * @param mixed $grant + * @param array $options + * @throws IdentityProviderException + * @return AccessTokenInterface + */ + public function getAccessToken($grant, array $options = []) + { + // withings requires the action to be 'requesttoken' when getting an access token + if (empty($options['action'])) { + $options['action'] = 'requesttoken'; + } + + return parent::getAccessToken($grant, $options); } /** @@ -113,6 +132,44 @@ protected function checkResponse(ResponseInterface $response, $data) } } + /** + * Prepares an parsed access token response for a grant. + * + * Custom mapping of expiration, etc should be done here. Always call the + * parent method when overloading this method. + * + * @param array $result + * @return array + */ + protected function prepareAccessTokenResponse(array $result) + { + if (!array_key_exists('status', $result)) { + throw new IdentityProviderException( + 'Invalid response received from Authorization Server. Missing status.', + 0, + $result + ); + } + + if ($result['status'] !== 0) { + throw new IdentityProviderException( + sprintf('Invalid response received from Authorization Server. Status code %d.', $result['status']), + 0, + $result + ); + } + + if (!array_key_exists('body', $result)) { + throw new IdentityProviderException( + 'Invalid response received from Authorization Server. Missing body.', + 0, + $result + ); + } + + return parent::prepareAccessTokenResponse($result['body']); + } + /** * Returns authorization parameters based on provided options. * Withings does not use the 'approval_prompt' param and here we remove it. diff --git a/test/src/Provider/WithingsTest.php b/test/src/Provider/WithingsTest.php index 5e1ce3c..b9d45ac 100644 --- a/test/src/Provider/WithingsTest.php +++ b/test/src/Provider/WithingsTest.php @@ -77,7 +77,7 @@ public function testGetBaseAccessTokenUrl() $params = []; $url = $this->provider->getBaseAccessTokenUrl($params); $uri = parse_url($url); - $this->assertEquals('/oauth2/token', $uri['path']); + $this->assertEquals('/v2/oauth2', $uri['path']); } public function testGetResourceOwnerDetailsUrl() @@ -91,7 +91,7 @@ public function testGetResourceOwnerDetailsUrl() public function testGetAccessToken() { $response = Mockery::mock('Psr\Http\Message\ResponseInterface'); - $response->shouldReceive('getBody')->andReturn('{"access_token":"mock_access_token", "token_type":"Bearer", "scope": "identify"}'); + $response->shouldReceive('getBody')->andReturn('{"status":0, "body":{"access_token":"mock_access_token", "token_type":"Bearer", "scope":"identify", "refresh_token":"mock_refresh_token", "user_id":"mock_user_id"}}'); $response->shouldReceive('getHeader')->andReturn(['content-type' => 'json']); $response->shouldReceive('getStatusCode')->andReturn(200); $client = Mockery::mock('GuzzleHttp\ClientInterface'); @@ -99,8 +99,8 @@ public function testGetAccessToken() $this->provider->setHttpClient($client); $token = $this->provider->getAccessToken('authorization_code', ['code' => 'mock_authorization_code']); $this->assertEquals('mock_access_token', $token->getToken()); + $this->assertEquals('mock_refresh_token', $token->getRefreshToken()); $this->assertNull($token->getExpires()); - $this->assertNull($token->getRefreshToken()); $this->assertNull($token->getResourceOwnerId()); }