Aerendir
Aerendir

Reputation: 6379

eBay REST API: invalid_request when exchanging the authorization code for an access token

I'm trying to connect to the eBay APIs through their new REST API.

I'm using a very simple script to test the flow and I'm using Guzzle.

The guide I'm following is this.

But when it's time to exchange the authorization code with an access token I ever receive the following response:

{"error":"invalid_request","error_description":"request is invalid","error_uri":null}

I really don't know what to try to make this work.

This is the code I'm using:

<?php

...

if (isset($_GET['code'])) {
    $client = new \GuzzleHttp\Client();

    $authorization = base64_encode($appId . ':' . $certId);
    $code = urlencode($_GET['code']);
    $body = 'grant_type=authorization_code&code=' . $code . '&redirect_uri=' . $ruName;

    $options = [
        \GuzzleHttp\RequestOptions::HEADERS => [
            'Content-Type' => 'application/x-www-form-urlencoded',
            'Authorization' => 'Basic ' . $authorization,
        ],
        \GuzzleHttp\RequestOptions::BODY => $body,
        \GuzzleHttp\RequestOptions::DEBUG => true,
    ];

    try {
        $response = $client->post('https://api.sandbox.ebay.com/identity/v1/oauth2/token', $options);
        die(dump($response->getBody()->__toString(), $response));
    } catch (\Exception $e) {
        die(dump($e,$_GET, $authorization, $body, $options));
    }
}

// Start the authentication redirecting the user to the eBay's sign-in page
$get_request_token_url = 'https://signin.sandbox.ebay.com/authorize'
    . '?client_id=' . $appId
    . '&redirect_uri=' . $ruName
    . '&response_type=code'
    // Scope for User
    . '&scope=' . urlencode(
        'https://api.ebay.com/oauth/api_scope '.
        'https://api.ebay.com/oauth/api_scope/sell.account.readonly '.
        'https://api.ebay.com/oauth/api_scope/sell.account '
    );
header('Location: ' . $get_request_token_url);

As the documentation is ambigous, I've also tried to set the on-time/temporary code returned by eBay directly in the query string (with all the other parameters that should be in the body). I've tried also to send them both in the body and appending them to the query_string but nothing seems to work...

I really don't know what other to try.

Anyone can help please?

Upvotes: 1

Views: 2515

Answers (1)

Ololo
Ololo

Reputation: 1097

I've used The League of Extraordinary Packages OAuth 2.0 Client but patched it a bit for Ebay compatibility:

Ebay Provider class:

namespace Library\Ras\OAuth2\Client\Provider;

use League\OAuth2\Client\Provider\GenericProvider;

/**
 * Class Ebay
 * @package Library\Ras\OAuth2\Client\Provider
 */
class EbayProvider extends GenericProvider
{

    protected function getAccessTokenOptions(array $params)
    {
        $options = [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/x-www-form-urlencoded',
                'Authorization' => sprintf(
                    'Basic %s',
                    base64_encode(sprintf('%s:%s', $params['client_id'], $params['client_secret']))
                ),
            ],
        ];

        unset($params['client_id'], $params['client_secret']);

        if ($this->getAccessTokenMethod() === self::METHOD_POST) {
            $options['body'] = $this->getAccessTokenBody($params);
        }

        return $options;
    }
}

If you are using Guzzle < 6.0, then custom request factory is needed:

namespace Library\Ras\OAuth2\Tool;

use GuzzleHttp\Message\MessageFactory;
use GuzzleHttp\Message\Request;
use League\OAuth2\Client\Tool\RequestFactory as BaseRequestFactory;

/**
 * Class RequestFactory
 * @package Library\Ras\OAuth2\Tool
 */
class RequestFactory extends BaseRequestFactory
{

    /**
     * Creates a request using a simplified array of options.
     *
     * @param  null|string $method
     * @param  null|string $uri
     * @param  array $options
     *
     * @return Request
     */
    public function getRequestWithOptions($method, $uri, array $options = [])
    {
        $factory = new MessageFactory();
        return $factory->createRequest($method, $uri, $options);
    }
}

And finally:

require __DIR__ . '/../vendor/autoload.php';

$client = new \Library\Ras\OAuth2\Client\Provider\EbayProvider([
    'clientId' => '<clientId>',
    'clientSecret' => '<clientSecret>',
    'redirectUri' => '<RUName>',
    'urlAuthorize' => 'https://signin.ebay.com/authorize',
    'urlAccessToken' => 'https://api.ebay.com/identity/v1/oauth2/token',
    'urlResourceOwnerDetails' => '',
    'scopeSeparator' => ' ',
    'scopes' => [
        'https =>//api.ebay.com/oauth/api_scope',
        'https =>//api.ebay.com/oauth/api_scope/buy.order.readonly',
        'https =>//api.ebay.com/oauth/api_scope/buy.order',
    ],
]);

// Only if your Guzzle version is < 6.0
$client->setRequestFactory(new \Library\Ras\OAuth2\Tool\RequestFactory());

if (array_key_exists('code', $_GET)) {
    $applicationToken = $_GET['code'];
    $accessToken = $client->getAccessToken('authorization_code', [
        'code' => $applicationToken,
    ]);
    echo 'User access token: ' . $accessToken;
} else {
    $url = $client->getAuthorizationUrl();
    header('Location: ' . $url);
}

Upvotes: 2

Related Questions