davidtsadler / ebay-sdk-php

An eBay SDK for PHP. Use the eBay API in your PHP projects.
Apache License 2.0
349 stars 341 forks source link

Error when get User tokens: Status Code: 400 invalid_grant #212

Closed congloi closed 4 years ago

congloi commented 6 years ago

Hi,

I try get user token but get error.

$service = new Services\OAuthService([ 'credentials' => [ 'appId' => '111', 'certId' => '222', 'devId' => '333', ], 'ruName' => 'foo' ]);

$url = $service->redirectUrlForUser([ 'state' => 'bar', 'scope' => [ 'https://api.ebay.com/oauth/api_scope/sell.fulfillment' ] ]);

When I got url, paste it on browser, login ebay, grand permision, and got return url with code v^1.1#i^1#f^0#I^3#r^1#p^3#t^U............

and next step, I call this function to get user token but got error:

$response = $service->getUserToken(new Types\GetUserTokenRestRequest([ 'code' => 'v^1.1#i^1#f^0#I^3#r^1#p^3#t^U............' ]));

printf("\nStatus Code: %s\n\n", $response->getStatusCode()); if ($response->getStatusCode() !== 200) { printf( "%s: %s\n\n", $response->error, $response->error_description ); } else { printf( "%s\n%s\n%s\n%s\n\n", $response->access_token, $response->token_type, $response->expires_in, $response->refresh_token ); }

get the error: Status Code: 400 invalid_grant: the provided authorization grant code is invalid or was issued to another client

can tell me where I wrong, I try search and some solution tell encode "code" string before getUserToken, but it still not work.

help me. thank

michabbb commented 6 years ago

so this, it not the problem ?

michabbb commented 6 years ago

maybe the parameter grant_type is missing, the docs say:

Request to get a User access token
  HTTP method:   POST
  URL (Sandbox): https://api.sandbox.ebay.com/identity/v1/oauth2/token

  HTTP headers:
    Content-Type = application/x-www-form-urlencoded
    Authorization = Basic 

  Request body (wrapped for readability):
    grant_type=authorization_code &
    code=&
    redirect_uri=

grant_type=authorization_code

congloi commented 6 years ago

thank @michabbb but I added grant_type parameter but still got same old error!

michabbb commented 6 years ago

in cases like this, don´t focus too much on this SDK. do the whole thing manually with postman and compare the requests with the one this SDK is doing, than you will see a difference somewhere.

buddyy93 commented 6 years ago

has there been any solutions for this? please help if there is a way to fix it

michabbb commented 6 years ago

@buddyy93 there is a way: do the whole oauth calls by yourself, not with the SDK. check your credentials and if everything is working, THEN use the SDK and compare the calls (request, url, header).

buddyy93 commented 6 years ago

@michabbb would you mind showing me the example codes please? i'm new to ebay sdk, i've been reading documentations but it's quite confusing.

congloi commented 6 years ago

@buddyy93 here my full code, it's working.

 $service = new OAuthService([
        'credentials' => [
            'appId'  => 'your_appid',
            'certId'  => 'your_certid',
            'devId'  => 'your_devid'
        ],
         'ruName'  => 'your_ruName'
    ]);

//Get GrandCode first

    public function postGrandCode(){
    $service = //above
    $url =  $service->redirectUrlForUser([
        'state' => 'bar',
        'scope' => [
            'https://api.ebay.com/oauth/api_scope/sell.fulfillment',
            'https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly' //You can ad more sope here
        ]
    ]);
    return $url;
}

Enter url link on browser, login ebay, accept permision and will got grandcode

Now we have grand code, we will get auth code.

    public function getUserToken($grand_code){
    $service = //above

    $grand_code = urldecode(urldecode($grand_code));

    $response = $service->getUserToken(new GetUserTokenRestRequest([
        'code' => $grand_code
    ]));

    if ($response->getStatusCode() !== 200) {

        $data['status'] = $response->error;
        $data['msg'] = $response->error_description;

    } else {
        $data['status'] = 'success';
        $data['access_token'] = $response->access_token;
        $data['refresh_token'] = $response->refresh_token;
    }
    return $data;
}

Save access_token and refresh_token to database, because access_token only active in 2 hours after create, so we need fresh_token to update access_token.

now we get orders from ebay

     $service = new FulfillmentService([
        'authorization' => $ebay_access_token
    ]);

    $request = new GetOrdersRestRequest([]);
    $response = $service->getOrders($request);

    if ($response->getStatusCode() !== 200) {
        dd( $response->error.': '.$response->error_description);
    } else {
     foreach ($response->orders as $ebayOrder){
       //your action here
     }
   }
michabbb commented 6 years ago

@buddyy93 you can test your oauth stuff this way very easy:

13-08-2018-04-32-39

that´s the URL users can use to connect their account with your app. you can try this with your private ebay account for test. you call this URL, login with your regular ebay credentials, then you will be redirect to the redirect url in that setup, you can use your own github page for testing, i.e. https://github.com/buddyy83 - let´s say you use your github url, you will be redirect to (just an example):

https://github.com/buddyy93/?code=v%5E1.1%23i%5E1%23f%5E0%23p%5E3%23r%5E1%23I%5E3%23t%5EUl41Xzg6Rj77g7g7g7guM3MDkzM0Q5Njc2MDVCRkU3QkFDR&expires_in=299

in that URL you have a code you need to extract, this code expire in expires_in (see url) seconds. you need to url_decode that code, the you will get this:

v^1.1#i^1#f^0#p^3#r^1#I^3#t^Ul41Xzg6Rj77g7g7g7guM3MDkzM0Q5Njc2MDVCRkU3QkFDR (just an example)

as described here, you have to make a call to get access_token and refresh_token from the user:

https://developer.ebay.com/api-docs/static/oauth-client-credentials-grant.html

as i already said before.

then, with postman (also mentioned before) you can setup the call explained in the docs:

13-08-2018-04-41-32

redirect_uri = RuName (eBay Redirect URL name) (from your developer account page) code = the code you got after the ebay user login, when you get redirected - from the url

the header of this call is also explained at the ebay docs:

13-08-2018-04-44-45

Authorization = Basic <B64-encoded_oauth_credentials> Basic <B64-encoded_oauth_credentials> = Base64-encoded OAuth credentials <client_id>:<client_secret> client_id = APP ID (Client ID from your app client_secret = Cert ID (Client Secret) from your app

after sending this call, you get a valid access_token and refresh_token.

the best, you can use postman to generate PHP code from that call:

<?php

$request = new HttpRequest();
$request->setUrl('https://api.ebay.com/identity/v1/oauth2/token');
$request->setMethod(HTTP_METH_POST);

$request->setHeaders(array(
  'Cache-Control' => 'no-cache',
  'Authorization' => 'Basic <client_id:client_secret> base64 encoded',
  'Accept' => 'application/json',
  'Content-Type' => 'application/x-www-form-urlencoded'
));

$request->setContentType('application/x-www-form-urlencoded');
$request->setPostFields(array(
  'grant_type' => 'authorization_code',
  'code' => '<code from redirect uri>',
  'redirect_uri' => '<RuName>'
));

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

if this is working for you and you fully understand the oauth process, THEN it´s time to use a SDK, otherwise you have no idea what´s going on and you will never be able to verify, fix or compare working and none working calls with eachother, in other words, you won´t be able to debug your stuff.

if this still in not clear enough, you should start from the very beginning and read the concept of oauth, the whole thing can be tricky if you never had anything todo with that 😏

buddyy93 commented 6 years ago

@congloi thank you so muchh! it worked like a charm :)

buddyy93 commented 6 years ago

@michabbb i haven't tried it though, but i like the details there you gave, will read it thoroughly, thank you

narraressan commented 6 years ago

Hi @buddyy93 @michabbb @congloi

I am getting this same error and while I was searching for possible fixes, I happen to find the thread.

I am already executing the very same requests (w/ my credentials from the ebay dashboard) in postman as you posted, but I am still getting the same issue.

{"error":"invalid_grant","error_description":"the provided authorization grant code is invalid or was issued to another client"}

Here is my javascript code embedded in my redirect link,

app.get('/', function(req, res) {
    var params = req.query

    axios({
        method: 'POST',
        url: 'https://api.ebay.com/identity/v1/oauth2/token',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Accept': 'application/json',
            'Cache-Control': 'no-cache',
            'Authorization': 'Basic XXXXXW5XXWQtXX9naXN0aWMtUFJELTI4XXX0ZTVlOS0zNGQzZmU1XXpQUkQtXXFmXXU1ZTk3YjUxLWE4MGYtNGIzYy0XXXXXXXXXXXX='
        },
        data: qs.stringify({
            'grant_type': 'authorization_code',
            'redirect_uri': 'Xxxxx_Xxxxx-YyyyyYyy-Xxgist-oirla',
            'code': 'v^1.1#i^1#f^0#r^1#I^3#p^3#t^...VeMjYw'
        })
    })
    .then((response) => { res.json(error.response.data) })
    .catch((error) => { res.json(error.response.data) })

});

I am quite lost of what or where I went wrong. If you can point it out, it would be a great help!

Thank you.

michabbb commented 6 years ago

@narraressan some say, this error popped up because they encoded something twice. other say, because they used wrong scopes in the very first call, but if you use the call from the developer account:

02-09-2018-12-38-48

that shouldn´t happen. if you follow the steps of my detailed posting, i don´t see any reason why this shouldn´t work 😕 the next thing that comes into my mind, when the user calls the URL (you see in this screenshot) - thiscode has a very short lifetime. the call you are showing here, where u are using this code v^1.1#... needs to be made very quick, because of its short lifetime. you see the lifetime in the URL where you get the code from.

if nothing helps, you could provide your postman calls (without any real credentials) as an export-file:

i am running out of ideas 😏

narraressan commented 6 years ago

Good day!

Sorry for the late reply.

Actually, I think I got it working by just logging out my Ebay account. It seems that I can't get a new token with grant type authorization_code while having an existing account logged in. This case doesn't apply with grant type client_credentials though.

Weird scenario... :(

Anyway, thank you...

michabbb commented 6 years ago

@congloi i guess you can close your issue here

kristiancon commented 5 years ago

@michabbb's answer is the solution. I was having this problem for days. These are the steps that I followed to generate user access token:

(This should work, assuming you already setup your eBay Redirect URL name) I didn't put anything under "Your auth accepted URL" and "Your auth declined URL" since I don't have one, but this still works)

  1. log in to https://developer.ebay.com/my/auth/

  2. go to "Get a Token from eBay via Your Application"

  3. Select radio button OAuth

  4. Click Test Sign-in

  5. Then click "I Agree"

  6. Copy the code part of the url. URL-encoded authorization code value returned to you by eBay when the user granted their consent. i.e https://signin.ebay.com/ws/eBayISAPI.dll?ThirdPartyAuthSucessFailure&isAuthSuccessful=true&code={COPY THE STRING HERE}&expires_in=299

  7. decode the string you just copied using urldecode('string here').

  8. Go to postman then paste the decoded string in request body "code" key. Please see photo posted by @michabbb for complete headers and request body keys.

michabbb commented 5 years ago

hey all,

in the meantime, I created a little playground for ebay-oauth, feel free to play with it.