What is wrong with this OAuth request to the Pocket API? - ruby

I'm trying to build a simple script using the Pocket API and I'm getting a 400 bad request when following the documentation on the site. Here is what I get:
POST /v3/oauth/request?consumer_key=xxxxxx-
xxxxxxxxxxxxxxxxxxx&redirect_uri=http://localhost:3000/callback HTTP/1.1
Host: getpocket.com
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
I am using Postman and I am running the redirect_uri from the rails server.
Additional information:
Cache-Control →private
Connection →keep-alive
Content-Length →15
Content-Type →text/html; charset=UTF-8
Date →Mon, 21 Apr 2014 01:17:05 GMT
Expires →Thu, 19 Nov 1981 08:52:00 GMT
P3P →policyref="/w3c/p3p.xml", CP="ALL CURa ADMa DEVa OUR IND UNI COM NAV INT STA PRE"
Pragma →no-cache
Server →Apache
Status →400 Bad Request
X-Error →Missing consumer key.
X-Error-Code →138
X-Source →Pocket
In a search to find out which x-error code was giving me a 400, I found that it's giving me a missing consumer key. I'm at a loss since this is a brand new key and I am certainly using it correctly. Any thoughts?

You are sending the consumer_key and redirect_uri as url parameters ?consumer_key=xxxxxx..
The correct way is to send them as form-data parameters:

Related

QuickBooks API example shows usage of "curl" but it actually doesn't work or am I missing something

According to QuickBooks Ruby API documentation, it provides an example of using curl to submit a POST request to the authorization url obtained from Step 1, but right underneath it, it shows that if the web application doesn't support browsers, to use Playground or a web component.
My question is – is it actually possible to use the curl command as shown in the example? If I take the exact URL and try to establish a POST request, I get the following results:
bash-3.2$ curl -X POST "https://appcenter.intuit.com/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690"
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
bash-3.2$
Obviously it's trying to redirect to another URL, but the API documentation doesn't show the usage of the -L parameter to follow redirects. If I try to provide the -L parameter for curl to follow redirects, then I get the following response:
bash-3.2$ curl -X POST "https://appcenter.intuit.com/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690" -L
<HTML><HEAD>
<TITLE>Bad Request</TITLE>
</HEAD><BODY>
<H1>Bad Request</H1>
Your browser sent a request that this server could not understand.<P>
Reference #7.2500e8ac.1592267832.14229c52
</BODY>
</HTML>
Again, doesn't work even following redirects. If I append -I to the curl command, then I get the following:
bash-3.2$ curl -X POST "https://appcenter.intuit.com/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690" -LI
HTTP/2 301
date: Tue, 16 Jun 2020 00:37:17 GMT
content-type: text/html
content-length: 162
location: https://appcenter.intuit.com/app/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690
server: nginx
cache-control: no-store, no-cache, must-revalidate
strict-transport-security: max-age=3156000; includeSubDomains; preload
HTTP/2 302
date: Tue, 16 Jun 2020 00:37:17 GMT
content-type: text/plain;charset=utf-8
content-length: 406
location: https://accounts.intuit.com/index.html?partner_uid_button=google&offering_id=Intuit.sbg-fms.ippdevx&redirect_url=https%3A%2F%2Fappcenter.intuit.com%2Fapp%2Fconnect%2Foauth2%3Fclient_id%3D[redacted]%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%26response_type%3Dcode%26scope%3Dcom.intuit.quickbooks.accounting%26state%3Dbe17472c59724eb46bfe2690
server: nginx
strict-transport-security: max-age=15552000
intuit_tid: 1-5ee8143d-29a68cec2ec922da5c6be528
x-spanid: ad76586b-a5ac-41bd-b2df-022148a5a78b
x-amzn-trace-id: Self=1-5ee8143d-3aa839e8b2cf25d846078238;Root=1-5ee8143d-29a68cec2ec922da5c6be528
x-dns-prefetch-control: off
x-download-options: noopen
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
cache-control: private,no-cache,no-store,pre-check=0,post-check=0,must-revalidate
expires: -1
pragma: no-cache
set-cookie: hosted-shell=%7B%22clientId%22%3A%22a4676677-5191-4eca-873e-34a04b5b1dd4%22%7D; Path=/; Expires=Fri, 14 Jun 2030 00:37:17 GMT; Secure
vary: Accept, Accept-Encoding
cache-control: no-store, no-cache, must-revalidate
strict-transport-security: max-age=3156000; includeSubDomains; preload
HTTP/2 411
server: AkamaiGHost
mime-version: 1.0
content-type: text/html
content-length: 223
expires: Tue, 16 Jun 2020 00:37:17 GMT
date: Tue, 16 Jun 2020 00:37:17 GMT
If I take the same URL and request it via a web browser, then it just takes me to the redirect callback URL as it's supposed to. I can't figure out why curl isn't doing the same thing. I don't understand what it means by "web component" if I can't even replicate the same thing via curl. I also have another web module that I'm using for GET and POST requests, and they're bringing me to an HTTP200 but not the callback URL.
Any idea how I could accomplish getting this authorization token from the redirect callback URL like it does in the web browser? Here's another example of me trying to do this via the web component in the Ruby script:
[3] pry(#<QuickBooksAPI>)> grant_url
=> "https://appcenter.intuit.com/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690"
[4] pry(#<QuickBooksAPI>)> response = WebRequest.new.get_request(grant_url)
=> #<Net::HTTPMovedPermanently 301 Moved Permanently readbody=true>
[5] pry(#<QuickBooksAPI>)> response['Location']
=> "https://appcenter.intuit.com/app/connect/oauth2?client_id=[redacted]&redirect_uri=http%3A%2F%2Flocalhost&response_type=code&scope=com.intuit.quickbooks.accounting&state=be17472c59724eb46bfe2690"
[6] pry(#<QuickBooksAPI>)> response = WebRequest.new.get_request(response['Location'])
=> #<Net::HTTPFound 302 Found readbody=true>
[7] pry(#<QuickBooksAPI>)> response['Location']
=> "https://accounts.intuit.com/index.html?partner_uid_button=google&offering_id=Intuit.sbg-fms.ippdevx&redirect_url=https%3A%2F%2Fappcenter.intuit.com%2Fapp%2Fconnect%2Foauth2%3Fclient_id%3D[redacted]%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%26response_type%3Dcode%26scope%3Dcom.intuit.quickbooks.accounting%26state%3Dbe17472c59724eb46bfe2690"
[8] pry(#<QuickBooksAPI>)> response = WebRequest.new.get_request(response['Location'])
=> #<Net::HTTPOK 200 OK readbody=true>
[9] pry(#<QuickBooksAPI>)> response.uri
=> #<URI::HTTPS https://accounts.intuit.com/index.html?partner_uid_button=google&offering_id=Intuit.sbg-fms.ippdevx&redirect_url=https%3A%2F%2Fappcenter.intuit.com%2Fapp%2Fconnect%2Foauth2%3Fclient_id%3D[redacted]%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%26response_type%3Dcode%26scope%3Dcom.intuit.quickbooks.accounting%26state%3Dbe17472c59724eb46bfe2690>
This time it sends me to a 200 but it never actually sends me to the callback/redirect URL.
I'm just simply trying to complete step 2 but cannot do so without a browser it seems, even using "web components" and curl.
Am I just going to have to manually use OAuth Playground and continuously just refresh my token since my API is all backend and no front-end/user redirect, etc.?
The OAuth grant flow needs your end user to grant your authenticate your application before you call API using access tokens. So here is what you process would look like
Present your user with a Connect to Intuit (or equivalent) button
User Clicks on the button and goes through authentication on intuit website (seems like the first bit of code you have inserted in your question. This cannot be automated)
Intuit redirects to the redirect url with a authorization_code
Rest is automated - Your browser or server takes the authorization_code from the url, combines it with a few other parameters and requests for an access_token
You can then continue to use the access_token to make your calls on behalf of the end user.
From Step3. onwards you can use curl to process all of it. Hope this helps :)
EDIT
No, In your case you would use OAuth differently. Using the Oauth Playground will take create an initial access_token for you. Steps 1-4 are taken care of.
Now you can use this token to authenticate all your API calls. However, the token will expire. So when you do get an expired response then you have to do a curl to fetch a new token using the info here...
https://developer.intuit.com/app/developer/qbo/docs/develop/authentication-and-authorization/oauth-2.0#refresh-the-token

JMETER 403 when uploading a file but needs to be logged in

So I am trying to test the file upload function of this website: http://the-v.net/en/vtube/upload-video through JMETER but to be successful, the user has to be logged in through this form: http://the-v.net/login, Now, I think this is a parameter-based authentication which could be solved by defining a valid username and password in the HTTP Authorization Manager config element, but even doing so I keep getting this error:
Thread Name: Thread Group 1-1
Sample Start: 2018-01-30 20:11:06 CST
Load time: 1373
Connect Time: 214
Latency: 1167
Size in bytes: 19151
Sent bytes:134
Headers size in bytes: 768
Body size in bytes: 18383
Sample Count: 1
Error Count: 1
Data type ("text"|"bin"|""): text
Response code: 403
Response message: Forbidden
Response headers:
HTTP/1.1 403 Forbidden
Date: Tue, 30 Jan 2018 12:11:06 GMT
Server: Apache/2.4.23 (Win64) PHP/5.6.25
X-Powered-By: PHP/5.6.25
X-Drupal-Cache: MISS
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Cache-Control: public, max-age=900
X-Content-Type-Options: nosniff
Content-Language: en
X-Frame-Options: SAMEORIGIN
X-Generator: Drupal 7 (http://drupal.org)
Link: <http://the-v.net/en/vtube/warning>; rel="canonical",<http://the-v.net/en/vtube/warning>; rel="shortlink",<http://the-v.net/sites/all/themes/vtube17/favicon.png>; rel="shortcut icon"
Etag: "1517314266-0"
Last-Modified: Tue, 30 Jan 2018 12:11:06 GMT
Vary: Cookie,Accept-Encoding
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
HTTPSampleResult fields:
ContentType: text/html; charset=utf-8
DataEncoding: utf-8
Any idea on how can I solve this? Thanks
I would suggest you record the upload in the browser and look in View Results Tree the headers/ coookies that are transmitted.
You can use File > Template. > Recording
Read:
http://jmeter.apache.org/usermanual/jmeter_proxy_step_by_step.html
You are most probably missing:
A header
A cookie
A parameter
You need to be logged in in order to be able to upload anything. HTTP Authorization Manager won't help as it is designed to deal with protocol level authentication and you need cookie-based one.
Add HTTP Cookie Manager to your Test Plan
Pay attention to form_build_id dynamic parameter you need to pass along with credentials during login request
So your test plan should look like:
1st HTTP Request - open login page
Post-Processor (i.e. CSS/JQuery Extractor to fetch form_build_id
2nd HTTP Request - perform login - provide credentials and the form_build_id from the previous step. You will also need to pass form_id parameter with the value of MYFORM_form
3rd HTTP Request - perform the upload.

Unauthorized CSRF validation failed in jMeter testing

I'm new to jMeter testing. I want to test the field update on UI. So When I run my test I'm getting the CSRF validation error. How can I resolve this. My test plan looks as,
And the sampler result is as follows,
Thread Name: Thread Group 1-1
Sample Start: 2014-11-18 23:37:49 IST
Load time: 688
Latency: 688
Size in bytes: 483
Headers size in bytes: 457
Body size in bytes: 26
Sample Count: 1
Error Count: 1
Response code: 401
Response message: Unauthorized : CSRF validation failed
Response headers:
HTTP/1.1 401 Unauthorized : CSRF validation failed
Date: Tue, 18 Nov 2014 18:08:07 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.5
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Tue, 18 Nov 2014 18:08:07 +0000
Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0
ETag: "1416334087"
Vary: Accept
Content-Length: 26
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json
Why do we get CSRF validation error and how to resolve it.
CSRF stands for Cross-site request forgery and you're getting CSRF Validation error due to missing mandatory dynamic request parameter, usually a Cookie or a Header.
I would suggest executing your scenario in i.e. Firefox Browser with HttpFox or FireBug extension enabled and inspect request details. CSRF token usually comes as a cookie in server's response and needs to be passed as a header or request parameter. So it is similar to usual correlation. So the flow should look as follows:
First HTTP Request: open first page
Extract CSRF token from response via one of the following Post Processors
Regular Expression Extractor
XPath Extractor
CSS/JQuery Extractor
Second HTTP Request: open second page (CSRF-protected). Add the token, extracted in step 2 to one of the following:
HTTP Request Parameter
HTTP Header Manager
HTTP Cookie Manager
Depending on where your server expects the token to live.
For the future, looking at your "localhost" server name - don't run JMeter performance tests on the same machine where application lives.

How to check user token limits?

How to check user token limits?
and why, when the maximum number of queries, requests continue to send?
Maximal limit is 5000 requests.
The response header for Instagram API has information on API limit and how much has been used.
Look for X-Ratelimit-Remaining and X-Ratelimit-Limit
Cache-Control:private, no-cache, no-store, must-revalidate
Connection:keep-alive
Content-Encoding:gzip
Content-Language:en
Content-Length:10117
Content-Type:application/json; charset=utf-8
Date:Thu, 20 Mar 2014 17:18:46 GMT
Expires:Sat, 01 Jan 2000 00:00:00 GMT
Pragma:no-cache
Server:nginx
Max-Age=31449600; Path=/
Vary:Cookie, Accept-Language, Accept-Encoding
X-Ratelimit-Limit:5000
X-Ratelimit-Remaining:4995
If you exceed the limit then you will get a HTTP 400 response, with a JSON response that has error_message that API limit has exceeded.
The API documentations says:
Be nice. If you're sending too many requests too quickly, we'll send
back a 503 error code (server unavailable).
So I guess you should look for a 503 as your indication that you've hit the limit. I haven't actually verified that this is the case, but it appears they have an Apigee front end, so I suspect it would work as stated.

What would cause SmartCloud to redirect a REST call to a login page?

I am not using the SBT, but making direct REST calls with Abdera to the current version of Connections on IBM SmartCloud. REST URL in question: https://apps.na.collabserv.com/search/serviceconfigs
Observations
When testing from my laptop (using Firefox and the REST client add-on,) this works as expected. I get back an ATOM feed.
When testing from a server (on a different network,) using the same method (Firefox + REST client,) I get back HTML that is a log-in page.
In addition, I get this same result when I call the URL from a Java program on the same server.
In all cases, I am using the same credentials with basic authentication.
Update: If I log into SmartCloud first, on a separate tab in Firefox on the server, then call the URL as before, from another tab, it works. I get the ATOM feed as desired. Naturally, this is unsuitable as a solution, but I present it as additional information that could lead to an actual solution.
Update: Further testing shows that the local (laptop) log-in exhibits the same behavior as the server. A form-based log-in is required from the same browser, then subsequent REST calls work.
Update: Here is a relevant simplified code snippet:
private static Abdera ABDERA = new Abdera();
private static AbderaClient ABDERA_CLIENT = new AbderaClient(ABDERA);
...
String host = "https://apps.na.collabserv.com";
ABDERA_CLIENT.addCredentials(host, AuthScope.ANY_REALM, "basic", new UsernamePasswordCredentials("user", "password"));
...
ClientResponse response = ABDERA_CLIENT.get("https://apps.na.collabserv.com/search/serviceconfigs");
Summary
It appears that something about the originating server or the call is causing SmartCloud to respond with a log-in page. Whereas, the same call and credentials from my laptop, work as expected.
Question
Where should I start to trouble-shoot this? How can I build the client credentials to allow programmatic log-in?
Response Headers
If it helps, here are the response headers that I get back in each case.
Unsuccessful
Status Code: 200 OK
Cache-Control: no-cache
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 1850
Content-Type: text/html
Date: Tue, 08 Oct 2013 14:15:03 GMT
Pragma: no-cache
Server: WebSEAL/6.1.1.3 (Build 110428)
Set-Cookie: PD-H-SESSION-ID=4_0_IR4***masked***oRKlJI;secure; Path=/; HttpOnly BIGipServerE3A-WebSEAL-80-fe=2132806922.20480.0000;secure; path=/
Vary: Accept-Encoding
p3p: CP="NON CUR OTPi OUR NOR UNI"
Successful
Status Code: 200 OK
Cache-Control: public, max-age=86400, s-maxage=86400, no-cache=set-cookie, private, must-revalidate
Content-Encoding: gzip
Content-Language: en-US
Content-Length: 1164
Content-Type: application/atom+xml; charset=UTF-8
Date: Mon, 07 Oct 2013 17:21:12 GMT
Expires: Tue, 08 Oct 2013 17:21:12 GMT
Server: WebSphere Application Server/8.0
Vary: Accept-Encoding
p3p: CP="NON CUR OTPi OUR NOR UNI"
x-lconn-auth: true
x-powered-by: Servlet/3.0
#Grant is your login using SAML? I could see this redirect happening. also could be TFIM related... maybe you should grab the auth on a different page, store the cookies, and then try connecting to the endpoint above.

Resources