Alex Alex - 15 days ago 5
PHP Question

PHP oAuth POST requests

Having a little trouble getting my oAuth POST requests to return a workable response. Any thoughts would be greatly appreciated.

$request = $provider->getAuthenticatedRequest(
'POST',
'https://graph.microsoft.com/v1.0/me/calendar/events',
$_SESSION['access_token'],
['body' =>
json_encode([
'Id' => null,
'Subject' => 'Test 54575',
'Start' => [
'DateTime' => '2016-11-17T02:00:00',
'TimeZone' => 'W. Europe Standard Time'
],
'End' => [
'DateTime' => '2016-11-17T04:00:00',
'TimeZone' => 'W. Europe Standard Time'
],
'Body' => [
'ContentType' => 'Text',
'Content' => 'estruyf'
],
'IsReminderOn' => false
])
]
);

$response = $provider->getResponse($request);


Error:

Fatal error: Uncaught UnexpectedValueException: Failed to parse JSON response: Syntax error in C:\projects\agentprocal\vendor\league\oauth2-client\src\Provider\AbstractProvider.php:663 Stack trace: #0 C:\projects\agentprocal\vendor\league\oauth2-client\src\Provider\AbstractProvider.php(704): League\OAuth2\Client\Provider\AbstractProvider->parseJson(NULL) #1 C:\projects\agentprocal\vendor\league\oauth2-client\src\Provider\AbstractProvider.php(643): League\OAuth2\Client\Provider\AbstractProvider->parseResponse(Object(GuzzleHttp\Psr7\Response)) #2 C:\projects\agentprocal\index.php(58): League\OAuth2\Client\Provider\AbstractProvider->getResponse(Object(GuzzleHttp\Psr7\Request)) #3 {main} thrown in C:\projects\agentprocal\vendor\league\oauth2-client\src\Provider\AbstractProvider.php on line 663


I've had no issues with creating tokens, or requesting data. If anybody needs any further information please don't hesitate to ask. Thanks!

(Using "league/oauth2-client": "^1.4")

Answer

Correct answer at the end

Problem

I'm currently looking inside that class AbstractProvider and it seems in vendor you have:

protected function parseJson($content) {
    $content = json_decode($content, true);
    if (json_last_error() !== JSON_ERROR_NONE) { // ! here that problem occurs
        throw new UnexpectedValueException(sprintf(
            "Failed to parse JSON response: %s",
            json_last_error_msg()
        ));
    }
    return $content;
}

which throws an exception that says there is some problem with parsing JSON because in another function we have:

protected function parseResponse(ResponseInterface $response) {
    $content = (string) $response->getBody();
    $type = $this->getContentType($response);

    if (strpos($type, 'urlencoded') !== false) { // ! here he checks header
        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) { // ! here it catch
        if (strpos($type, 'json') !== false) { // ! again he checks header
            throw $e; // ! and here it throw
        }
        return $content;
    }
}

Solution

It looks like you dont set up right headers.

So it seems if you add in your request something like:

$options['header']['Content-Type'] = 'application/x-www-form-urlencoded';

it should work, because it will just return a string, without trying to json_decode() in protected function parseJson($content) method.

In your code it will look like this:

$request = $provider->getAuthenticatedRequest(
    'POST',
    'https://graph.microsoft.com/v1.0/me/calendar/events',
    $_SESSION['access_token'],
    ['body' =>
        json_encode([
            'Id' => null,
            'Subject' => 'Test 54575',
            'Start' => [
                'DateTime' => '2016-11-17T02:00:00',
                'TimeZone' => 'W. Europe Standard Time'
            ],
            'End' => [
                'DateTime' => '2016-11-17T04:00:00',
                'TimeZone' => 'W. Europe Standard Time'
            ],
            'Body' => [
                'ContentType' => 'Text',
                'Content' => 'estruyf'
            ],
            'IsReminderOn' => false
        ]),
     'header' => [
         'Content-Type' => 'application/x-www-form-urlencoded', // set header
         ],
    ],
);

$response = $provider->getResponse($request);

If you want to get a response in JSON you should set your headers like:

$options['header']['Accept'] = `application/json`;
$options['header']['Content-Type'] = `application/json`;

And it would look in your code like:

$request = $provider->getAuthenticatedRequest(
    'POST',
    'https://graph.microsoft.com/v1.0/me/calendar/events',
    $_SESSION['access_token'],
    ['body' =>
        json_encode([
            'Id' => null,
            'Subject' => 'Test 54575',
            'Start' => [
                'DateTime' => '2016-11-17T02:00:00',
                'TimeZone' => 'W. Europe Standard Time'
            ],
            'End' => [
                'DateTime' => '2016-11-17T04:00:00',
                'TimeZone' => 'W. Europe Standard Time'
            ],
            'Body' => [
                'ContentType' => 'Text',
                'Content' => 'estruyf'
            ],
            'IsReminderOn' => false
        ]),
     'header' => [
         'Content-Type' => 'application/json', // set content type as JSON
         'Accept' => 'application/json', // set what you expect in answer
         ],
    ],
);

$response = $provider->getResponse($request);

Update

After our chat conversation we got a solution. The problem was with a header and correct code is:

$body = [
            'Id' => null,
            'Subject' => 'Test 54575',
            'Start' => [
                'DateTime' => '2016-11-17T02:00:00',
                'TimeZone' => 'W. Europe Standard Time'
            ],
            'End' => [
                'DateTime' => '2016-11-17T04:00:00',
                'TimeZone' => 'W. Europe Standard Time'
            ],
            'IsReminderOn' => false
        ];

$options['body'] = json_encode($body);
$options['headers']['Content-Type'] = 'application/json;charset=UTF-8';

$request = $provider->getAuthenticatedRequest(
    'POST',
    'https://graph.microsoft.com/v1.0/me/calendar/events',
    $_SESSION['access_token'],
    $options
);

$response = $provider->getResponse($request);
Comments