I'm using PHPoAuthLib in order to connect to the QuickBooks API per their example
When I follow their example, the first request that I make to the API works perfectly:
$result = json_decode($quickbooksService->request($url));
echo 'result: <pre>' . print_r($result, true) . '</pre>';
However in their example they use $_GET['oauth_token'] and $_GET['oauth_verifier'] to request an access token, and these values are only available on the $_GET server variable during the single callback from QuickBooks Online immediately after my app has been authorized.
For future requests there are no such examples on PHPoAuthLib's docs, so I tried a quick homebrew solution:
Save the response from QBO somewhere
if (!empty($_GET['oauth_token']) {
file_put_contents("token.txt", json_encode([
'oauth_token' => $_GET['oauth_token'],
'oauth_verifier' => $_GET['oauth_verifier'],
'realm_id' => $_GET['realmId']
]));
}
Use that response again later
$token = json_decode(file_get_contents("token.txt"));
$quickbooksService->requestAccessToken(
$token->oauth_token,
$token->oauth_verifier
// $token->getRequestTokenSecret() is not necessary - it will be automatically populated
);
// At this point my app crashes and return a 500 error
// Further code does not run
The error I receive is:
TokenResponseException in StreamClient.php line 68:
Failed to request resource. HTTP Code: HTTP/1.1 401 Unauthorized
Remember that the token and verifier work perfectly if I use them immediately after the app is authorized. If I save them to a file and attempt to re-use them 30 seconds later, this happens.
I think it might be a fundamental misconception about OAuth 1.0
I don't think what you have is a correct OAuth implementation. Have you read the OAuth spec and implemented as it's defined there?
Once you have a request token and a verifier, you use those to get an access token.
That access token is then good for 6 months.
It looks like you're trying to use a short-lived request token to continually fetch access tokens instead. That won't work.
i.e. If you're doing this everytime you want to make another request:
$quickbooksService->requestAccessToken(
Then you're doing something wrong. You should be doing that ONCE every 6 months, and that's it.
Working code here:
https://github.com/consolibyte/quickbooks-php/blob/master/QuickBooks/IPP/IntuitAnywhere.php
https://github.com/consolibyte/quickbooks-php/blob/master/QuickBooks/IPP/OAuth.php
https://github.com/consolibyte/quickbooks-php
Spec is here:
http://oauth.net/core/1.0a/#auth_step3
Related
I requested authorization for a public application to be able to access store data via the Shopify API.
The store successfully authorized my application via an authorization request URL such as
https://some-store.myshopify.com/admin/oauth/authorize?client_id=123abc&scope=read_inventory%2Cread_products&redirect_uri=http%3A%2F%mysite.com%2Fauth.php&state=123456
and the response was passed back to my application. This response (containing the code that can be exchanged for a permanent access token) was mishandled by my application (an error on the page meant that the access token was not stored).
Everything I read regarding requesting these tokens involves authorization by the store - but given the store has already authorized my application, passed back the code and that code has already successfully been exchanged for a token: is there a way my application can request that same token or a fresh one using my API keys given that the application is already authorized?
The only method I currently can find for requesting a token requires starting back at the beginning and fetching a code for exchange etc.
I working in PHP and using Luke Towers' php shopify wrapper
This stage was completed successfully:
function check_authorization_attempt()
{
$data = $_GET;
$api = new Shopify($data['shop'], [
'api_key' => '123',
'secret' => '456',
]);
$storedAttempt = null;
$attempts = json_decode(file_get_contents('authattempts.json'));
foreach ($attempts as $attempt) {
if ($attempt->shop === $data['shop']) {
$storedAttempt = $attempt;
break;
}
}
return $api->authorizeApplication($storedAttempt->nonce, $data);
}
$response = check_authorization_attempt();
and I would have been able to read the access token from :
$access_token = $response->access_token;
But this was the stage at which my application hit an error in accessing a database in which to write said token.
I cannot repeat it without repeating the auth request because the data in $_GET that's passed to this function comes from Shopify's response to the shop owner authorizing the access, and includes amoung other things the code for exchange.
You have to re-ask for authorization. It is no one's fault but yours that your persistence layer code was incorrect. So there is nothing you can do to change that. Ensure your code works. Since the client has no token in your App persistence layer, your App will retry the authorization token exchange. They do not have to delete your App first. So basically, the next time your client tries to use the App, YES they will asked to approve it, but who cares, they will, and you'll get a good auth token to store. You have fixed your code (right), so that will work. You are one step closer to glory.
Shopify does return the Permanent Access Token, but the ACCESS_MODE must be "Offline" for the token to be permanent.
With ACCESS_MODE offline, your app receives the permanent access token
to make requests whenever you want, without the user's permission.
Documentation:
https://shopify.dev/tutorials/authenticate-with-oauth#step-2-ask-for-permission
https://shopify.dev/concepts/about-apis/authentication#api-access-modes
I got a problem with oAuth authentification in magento.
I used following guide to create connection:
http://www.magentocommerce.com/api/rest/authentication/oauth_authentication.html
First of all I granted all privileges for all accounts in magento / System / WebServices / REST ... Also I created oAuth Consumer. I got with it two variables (key and secret).
According the guide (Getting an Unauthorized Request Token) I configured RESTClient for Firefox. Selected oAuth 1.0 option, inserted data from magento and added them to headers.
And now I have something like that:
http://www.mg19.local/oauth/initiate
OAuth oauth_version="1.0",
oauth_signature_method="PLAINTEXT",
oauth_nonce="pzmp8IZuroEP6gf",
oauth_timestamp="1410271763",
oauth_consumer_key="9ad2067e70a4c3b799ab2799203b3e3b",
oauth_signature="a37633084e79432568181ef00410140e%26"
Then if I submit this, I will get following error:
Status Code: 400 Bad Request
oauth_problem=parameter_absent&oauth_parameters_absent=oauth_callback
I don't know the main purpose of the callback link, therefore I used random link. For example: http://www.mg19.local
When i submit
http://www.mg19.local/oauth/initiate/?oauth_callback=http://www.mg19.local
I got following result:
oauth_token=e00fc8386ba523bdd1d79a2fe61d59cb&oauth_token_secret=ca0d999010b2b149e2d51feefc328722&oauth_callback_confirmed=true
According the guide I moved to the 2nd step (User Authorization):
I copied data from the response to request. And forward the link:
http://www.mg19.local/oauth/authorize
I redirected to the following page:
Authorize application
Postman requests access to your account
After authorization application will have access to you account.
Authorize | Reject
And when I select Authorize I'm getting the following error:
An error occurred. Your authorization request is invalid.
Using xDebug I have found that the problem is near:
/**
* Load token object, validate it depending on request type, set access data and save
*
* #return Mage_Oauth_Model_Server
* #throws Mage_Oauth_Exception
*/
protected function _initToken()
{
....
} elseif (self::REQUEST_AUTHORIZE == $this->_requestType) {
if ($this->_token->getAuthorized()) {
$this->_throwException('', self::ERR_TOKEN_USED);
...
I'm not sure, but I think, once autorization finished successfully, then I moved from index to account area page and when authorization start again - it fail and I move on index again.
Please give any advice.
For what I see, the callback URL is the one that is messing up the whole thing. Callback is the most important link in OAuth. The callback should be a valid URL pointing to you site.
Once the user logs in auth server (Magneto in your case) Magneto will do a callback to the Callback URI you provided with the oauth_verifier. Like below:
/callback?oauth_token=tz2kmxyf3lagl3o95xnox9ia15k6mpt3&oauth_verifier=cbwwh03alr5huiz5c76wi4l21zf05eb0
Then your server should all the token API /oauth/token with the all the required Authorization headers below. Pasted from Magneto document link you provided
oauth_consumer_key - the Consumer Key value provided after the registration of the application.
oauth_nonce - a random value, uniquely generated by the application.
oauth_signature_method - name of the signature method used to sign the request. Can have one of the following values: HMAC-SHA1, RSA-SHA1, and PLAINTEXT.
oauth_signature - a generated value (signature).
oauth_timestamp - a positive integer, expressed in the number of seconds since January 1, 1970 00:00:00 GMT.
oauth_token - the oauth_token value (Request Token) received from the previous steps.
oauth_verifier - the verification code that is tied to the Request Token.
oauth_version - OAuth version.
Hope this makes it clear. Please read the sections User Authorization and Getting Access Token sections of the link you pasted.
I'm using Guzzle and had a real hard time with it. In my case it was failing because I was using oauth_callback instead of callback, it worked when I changed it to:
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Subscriber\Oauth\Oauth1;
$stack = HandlerStack::create();
$middleware = new Oauth1([
'consumer_key' => $key,
'consumer_secret' => $secret,
'token' => null,
'token_secret' => null,
'callback' => 'https://callback.co.uk'
]);
$stack->push($middleware);
$client = new Client([
'base_uri' => $magentoCredentials->shopUrl,
'handler' => $stack
]);
$res = $client->post('/oauth/initiate?oauth_callback', ['auth' => 'oauth']);
I had an implementation of OAuth working with Fitbit to pull data from fitbit's service. However they recently updated their service and now the request is failing whenever I try to get an access token.
They have made the following statement about the new requirement:
The solution is to OAuth sign the requests to <https://api.fitbit.com/oauth/request_token> and <https://api.fitbit.com/oauth/access_token> in a similar manner that all other calls to the Fitbit API are signed.
Requests to <https://api.fitbit.com/oauth/request_token> need to be signed with your application's consumer key and secret.
Requests to <https://api.fitbit.com/oauth/access_token> need to be signed with your application's consumer key and secret and the oauth_token and oauth_verifier received from the authorization callback.
I am using the PHP PECL OAuth library for OAuth requests. However I can't find a way to add additional parameters to the signature. I am trying the following but I'm not sure that this is the correct way to update the OAuth Signature:
$params['consumer_key'] = $this->consumer_key;
$params['consumer_secret'] = $this->consumer_secret;
$params['oauth_token'] = $this->oauth_token;
$params['oauth_verifier'] = $_REQUEST['oauth_verifier'];
$this->signature = $this->oauth->generateSignature('GET', $this->access_url, $params);
$this->access_token = $this->oauth->getAccessToken($this->access_url, $this->signature, $_REQUEST['oauth_verifier']);
The OAuth error I get is:
401
Invalid auth/bad request (got a 401, expected HTTP/1.1 20X or a redirect)
oauthoauth_signatureInvalid signature: FfvYDv5MSOfwcOwLZBJa0TlKS4Q=false
The signature which is stored from the code above shows that the proper signature should be:
[signature] => wlfzqPs4aEkTkHfqyaO65D/RW6o=
This is the "Headers Sent" piece of the debug information:
[headers_sent] => Authorization: OAuth oauth_session_handle="Frdnxw8oHe3BgNVi0Fy4jBXrZko%3D",
oauth_verifier="ss6nmke8elf3so66jg3auued49",
oauth_consumer_key="(my key)",
oauth_signature_method="HMAC-SHA1",
oauth_nonce="30463910852ea5cc2d04e60.71895372",
oauth_timestamp="1391090882",
oauth_version="1.0",
oauth_token="2cabd6beab341e332bdf8e522b6019ef",
oauth_signature="hULwWcQOl%2F8aYjh0YjR843iVXtA%3D"
I can't find anything in the documentation which explains how I can set the signature for OAuth to use with it's request. Any Help would be greatly appreciated!!!
Please let me know if you need more information!
I have found the issue.
It turns out I was not saving the oauth_token_secret being handed back and I was instead using the consumer secret.
Once I updated this, the process ran as expected.
I'm trying to get the list of all my friends from the Google plus via API. The user on whose behalf I'm doing this operation previously authorized my request and I got the auth token. I've tried the following code in php:
function CallAPI() {
$opts = array(
"http" => array(
"method" => "GET"
)
);
$url = 'https://www.googleapis.com/plus/v1/people/me/people/visible?key=XXXX';
$context = stream_context_create($opts);
$response = file_get_contents($url, false, $context);
var_dump($response);
}
but I keep receiving HTTP request failed! HTTP/1.0 401 Unauthorized. How can I prove that the user authorized my operations or what am I doing wrong?
Any help is much appreciated.
You need to authenticate the user to use the special keyword "me" so using your simple API key will not work (assuming the key passed is your simple key). Instead, you need to get an access token and pass that.
For a great example of how to do this in PHP using the PHP client library, try the quickstart:
https://developers.google.com/+/quickstart/php
If you are already getting an access token, you can call tokeninfo passing access token to get more information about who the user is associated with it:
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=ya29.xxxxxxxx...
At this point, you could call:
'https://www.googleapis.com/plus/v1/people/[useridfromaccesstoken]/people/visible?key=XXXX';
To verify that your API key is correct but I would recommend using the client library as demonstrated in the quickstart sample.
I am trying to write a small webapp that pulls data from Yammer. I have to go through Yammer's OAuth bridge to access their data. I tried using the Oauth php library and do the 3 way handshake. But at the last step, I get an error stating I have an invalid OAuth Signature.
Here are the series of steps:
The first part involves getting the request Token URL and these are the query parameters that I pass.
[oauth_version] => 1.0
[oauth_nonce] => 4e495b6a5864f5a0a51fecbca9bf3c4b
[oauth_timestamp] => 1256105827
[oauth_consumer_key] => my_consumer_key
[oauth_signature_method] => HMAC-SHA1
[oauth_signature] => FML2eacPNH6HIGxJXnhwQUHPeOY=
Once this step is complete, I get the request Token as follows:
[oauth_token] => 6aMcbRK5wMqHgZQsdfsd
[oauth_token_secret] => ro8AJxZ67sUDoiOTk8sl4V3js0uyof1uPJVB14asdfs
[oauth_callback_confirmed] => true
I then try to authorize the given token and token secret by passing the parameters to the authorize url.It takes me to Yammer's authentication page where I have allow my app to talk to Yammer.
Yammer then gives me a 4 digit code that I have to put back into my application which then tries to acquire the permanent access token. I pass the following information to the access token URL:
[oauth_version] => 1.0
[oauth_nonce] => 52b22495ecd9eba277c1ce6b97b00fdc
[oauth_timestamp] => 1256106815
[oauth_consumer_key] => myconsumerkey
[callback_token] => 61A7
[oauth_token] => 6aMcbRK5wMqHgZQsdfsd
[oauth_token_secret] => ro8AJxZ67sUDoiOTk8sl4V3js0uyof1uPJVB14asdfs
[oauth_callback_confirmed] => true
[oauth_signature_method] => HMAC-SHA1
[oauth_signature] => V9YcMDq2rP7OiZTK1k5kb/otMzA=
Here I am supposed to receive the Oauth Permanent access token, but instead I get a Invalid Oauth signature. I dont know what I am doing wrong. I use the same signaures to sign the request. Should I sign the request using the new token and secret? I tried that as well but to no avail. I even tried implementing this in java using signpost library and got stuck at the exact same place. Help Help!!
The callback_token was something Yammer introduced in response to an OAuth security advisory earlier this year. When OAuth 1.0a was released, it was instead named oauth_verifier. However, it's not unlikely that Yammer still supports their workaround but rename it and try again to be sure.
Also, the below is information from the Yammer Development Network yesterday:
Tomorrow we will be releasing some
changes to the Yammer API to
facilitate user network switching on
API clients. Most of the change is in
the OAuth Access Tokens call which
allows you to generate pre-authorized
OAuth access tokens for a given user.
One token will be generated for each
network they are in and your clients
switch networks by sending an API
request signed with the appropriate
token for that network.
I'm assuming that Yammer OAuth libraries might need to be updated per this change. I haven't taken a look at it yet.
Edit: My python-yammer-oauth library still works despite Yammer having changed things on their side.
Edit2: Could you try using signature method PLAINTEXT instead of HMAC-SHA1? I've had problems with Yammer and HMAC-SHA1.
I tried by using PLAINTEXT.. but for this method its giving me the same "Invalid OAuth signature" error even for requesting the token.
So is it possible to generate the access token we use HMAC-SHA1 and for accessing the actual API method i.e. for posting the message.. we use PLAINTEXT?
just found the problem!
I had forgotten to add an ampersand ("&") at the end of CONSUMER_SECRET. Perhaps this is your issue as well?