Description
Uncaught Exception "TypeError" with message: "Argument 1 passed to League\OAuth2\Client\Provider\AbstractProvider::prepareAccessTokenResponse() must be of the type array, string given
It happens because AbstractProvider::getParsedResponse
returns string when content can't be parsed.
// AbstractProvider::getAccessToken
// ...
$response = $this->getParsedResponse($request);
$prepared = $this->prepareAccessTokenResponse($response);
// ...
/**
* Sends a request and returns the parsed response.
*
* @param RequestInterface $request
* @return mixed
*/
public function getParsedResponse(RequestInterface $request)
{
try {
$response = $this->getResponse($request);
} catch (BadResponseException $e) {
$response = $e->getResponse();
}
$parsed = $this->parseResponse($response);
$this->checkResponse($response, $parsed);
return $parsed;
}
Attention to docs — "return mixed". It can not return "mixed" (though actually it is), because the result goes to prepareAccessTokenResponse
which receives array only.
/**
* 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 mixed $result
* @return array
*/
protected function prepareAccessTokenResponse(array $result)
Docs say param mixed $result
(was changed here 365e61c with no visible reason), but typehint says array $result
.
And the last thing — where mixed comes from?
/**
* Parses the response according to its content-type header.
*
* @throws UnexpectedValueException
* @param ResponseInterface $response
* @return array
*/
protected function parseResponse(ResponseInterface $response)
{
$content = (string) $response->getBody();
$type = $this->getContentType($response);
if (strpos($type, 'urlencoded') !== false) {
parse_str($content, $parsed);
return $parsed;
}
// Attempt to parse the string as JSON regardless of content type,
// since some providers use non-standard content types. Only throw an
// exception if the JSON could not be parsed when it was expected to.
try {
return $this->parseJson($content);
} catch (UnexpectedValueException $e) {
if (strpos($type, 'json') !== false) {
throw $e;
}
return $content;
}
}
return array
— one more lie here. Look at the catch block: value is considered unexpected only if type was "expected" — wut? Otherwise $content
is returned, which is string. This was called fallback on failure.
So, long story short
- provider returns some wierd response
- oauth2-client tries to parse it as json and fails to
- then the parse method returns a string (raw response body) instead of an exception or at least promised array
- string goes to another method with
array
typehint - ???
- TypeError (PHP 7)
I haven't done PR because I don't know what's the right solution in this situation. We should respect BC, I understand. But I'd just throw an exception despite any other condition: we tried to do something and failed — there is nothing we can do with it later.