Google oAuth2 unauthorized_client by refresh_token - perl

i'm trying to use an refresh token from the oAuth2 web redirect auth in my console perl script. The client id is the same and correct client id i used in my javascript an i checked it 5 times that it ist the same as i have in my google API's Console.
The client secret is checked two and it is correct.
The refresh token was created with approval_prompt=force&access_type=offline
Here is my perl sample code i use:
# -----------------------------------------------------------------------------------
my $CLIENT_ID = 'XXXXX.apps.googleusercontent.com';
my $CLIENT_SECRET = 'YYYYYYYYYYY';
# -----------------------------------------------------------------------------------
# TESTING
my $refresh_token = '1/is_5_minutes_old';
# -----------------------------------------------------------------------------------
my $string = '';
$string .= 'grant_type=refresh_token';
$string .= '&client_id=' . $CLIENT_ID;
$string .= '&client_secret=' . $CLIENT_SECRET;
$string .= '&refresh_token=' . $refresh_token;
$ua = LWP::UserAgent->new;
my $req =
HTTP::Request->new( POST => 'https://accounts.google.com/o/oauth2/token' );
$req->content_type('application/x-www-form-urlencoded');
$req->content($string);
print $string . "\n";
my $res = $ua->request($req);
print $res->as_string;
The response of it:
HTTP/1.1 400 Bad Request
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: close
Date: Mon, 02 Sep 2013 10:50:26 GMT
Pragma: no-cache
Server: GSE
Content-Type: application/json
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Alternate-Protocol: 443:quic
Client-Date: Mon, 02 Sep 2013 10:50:26 GMT
Client-Peer: 74.125.136.84:443
Client-Response-Num: 1
Client-SSL-Cert-Issuer: /C=US/O=Google Inc/CN=Google Internet Authority G2
Client-SSL-Cert-Subject: /C=US/ST=California/L=Mountain View/O=Google Inc/CN=accounts.google.com
Client-SSL-Cipher: RC4-SHA
Client-SSL-Warning: Peer certificate not verified
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
{
"error" : "unauthorized_client"
}
i hope you have an idea to help.
greatings

Invalid client usually means that the client ID and client secret don't match, or there is a typo in one of them (though you mention you've double checked this!). Nothing in your code looks wrong.
When you retrieve the refresh token, could you try putting the access token that comes along with it into the tokeinfo endpoint and making sure the values for client ID there match the ones you've configured with: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=
It might be worth dumping out the request to make sure there isn't a mistake in that (e.g. too short a content-length header or similar).

Dumping the request is key. To help , here is one I baked earlier..
==POST==
https://accounts.google.com/o/oauth2/token
refresh_token=1/_PEzU2m71wertwertwerJUtrtrytrytryf3trytryoCo
&client_id=612222222225
&client_secret=Q7334534543534yKLu
&grant_type=refresh_token
Are you using the short form of the client id, ie. just the number?

Related

Malformed Session ID Cookie

Set-Cookie: SESSIONID=836cfc64b5856712b040a0b1b3bf4237; Secure; HttpOnly
Set-Cookie: Watson-DPAT=gBJQjAG%2FYflxpHKCwJVswQPEBuUmikj38zzFm8UZNTbOERxbeXS4WVxBIT5JetJBkeO1RT16PNz6%2BI17oFrEqvxjny%2FifZRorvBxXVzDmFkRpfRLxxj6ZNvFCvuRL1DtfW3nL8Ne1QDwpuKQmNt8%2BD9vFk7bGjlaziHT0ZFhNffWJT7FRCWbuJAyjKd%2BQui2WTIl6B8KglPi6GG1buh5UPDE%2Bc8OvrqyAfJRfYOApRdx7kHhtHdxIV7g%2FzNExXhafScqxi4cWEa5Kg9YGcypr8SIO%2FD7WOq0KyERHUDkbZatH53CCii25it5XD0plnt3cVc4bWs8tXkMT82V9DwCYULto64L%2BgNh30iTpyv72xOIfHeZTt2KISfhXMy6z86ueaJZzNd4nS6rwc7s2E8ldxwYLXrCU996xsLmzPYbGSzaeFLplG7c%2BCxzTlAll5fn8eMMbGn30W%2BrXLNtcaJ3lRK2nvzQCim1GhMdqoOvOcSvPWiJoVBrF8lc75eGSr8C%2Fovq20fOk3NDw4f0UPfBEGZYuAtXjonU7QdRhSgLRXxKyGvcYHEWeWUOQ2kvtI2m%2FRD%2BMRx9384p1v6uu8XfaU16IqoidV0Vew3MLPW4fxcOWRqnWKy0iIYbIJrWVcigloIy%2FNxgO7oHW7aacgH1u8IluAURz5AiE1Bej4l%2FjAI91IUTEssbg6fsXd3AqmlkixDglDJBgTEtMoXhXVyDjvJSaVUqdFTokP3YcRNhlTzqDQ3vG8txTLzECsyQHZ7DgWp%2B98P3zjvtad9xB%2BDzXhF4CaUB7ve99bWO5FO1DU3KRhx7pEAKGselDCoxTOkjIhEMMJbeQrbC1QWJ4uR9KlBPBdIbShd3; path=/speech-to-text/api; secure; HttpOnly
The request to create the Speech to Text session works.
{
"recognize": "https://stream.watsonplatform.net/speech-to-text/api/v1/sessions/836cfc64b5856712b040a0b1b3bf4237/recognize",
"recognizeWS": "wss://stream.watsonplatform.net/speech-to-text/api/v1/sessions/836cfc64b5856712b040a0b1b3bf4237/recognize",
"observe_result": "https://stream.watsonplatform.net/speech-to-text/api/v1/sessions/836cfc64b5856712b040a0b1b3bf4237/observe_result",
"session_id": "836cfc64b5856712b040a0b1b3bf4237",
"new_session_uri": "https://stream.watsonplatform.net/speech-to-text/api/v1/sessions/836cfc64b5856712b040a0b1b3bf4237"
}
Then I try to get the status of the session to make sure the state is "initialized" but I get a "Malformed Session ID Cookie" error.
GET /speech-to-text/api/v1/sessions/836cfc64b5856712b040a0b1b3bf4237/recognize HTTP/1.1\x0d
Content-Length: 0\x0d
Accept-Encoding: gzip\x0d
Authorization: Basic OGIyMTk0MDYtYWYzYS00YTFhLWExYmMtZDA3ZjNlNTY2Y2JmOm1lYmpBaG1ndkhMSw==\x0d
Cookie: SESSIONID=836cfc64b5856712b040a0b1b3bf4237; Watson-DPAT=gBJQjAG%2FYflxpHKCwJVswQPEBuUmikj38zzFm8UZNTbOERxbeXS4WVxBIT5JetJBkeO1RT16PNz6%2BI17oFrEqvxjny%2FifZRorvBxXVzDmFkRpfRLxxj6ZNvFCvuRL1DtfW3nL8Ne1QDwpuKQmNt8%2BD9vFk7bGjlaziHT0ZFhNffWJT7FRCWbuJAyjKd%2BQui2WTIl6B8KglPi6GG1buh5UPDE%2Bc8OvrqyAfJRfYOApRdx7kHhtHdxIV7g%2FzNExXhafScqxi4cWEa5Kg9YGcypr8SIO%2FD7WOq0KyERHUDkbZatH53CCii25it5XD0plnt3cVc4bWs8tXkMT82V9DwCYULto64L%2BgNh30iTpyv72xOIfHeZTt2KISfhXMy6z86ueaJZzNd4nS6rwc7s2E8ldxwYLXrCU996xsLmzPYbGSzaeFLplG7c%2BCxzTlAll5fn8eMMbGn30W%2BrXLNtcaJ3lRK2nvzQCim1GhMdqoOvOcSvPWiJoVBrF8lc75eGSr8C%2Fovq20fOk3NDw4f0UPfBEGZYuAtXjonU7QdRhSgLRXxKyGvcYHEWeWUOQ2kvtI2m%2FRD%2BMRx9384p1v6uu8XfaU16IqoidV0Vew3MLPW4fxcOWRqnWKy0iIYbIJrWVcigloIy%2FNxgO7oHW7aacgH1u8IluAURz5AiE1Bej4l%2FjAI91IUTEssbg6fsXd3AqmlkixDglDJBgTEtMoXhXVyDjvJSaVUqdFTokP3YcRNhlTzqDQ3vG8txTLzECsyQHZ7DgWp%2B98P3zjvtad9xB%2BDzXhF4CaUB7ve99bWO5FO1DU3KRhx7pEAKGselDCoxTOkjIhEMMJbeQrbC1QWJ4uR9KlBPBdIbShd3\x0d
User-Agent: Mojolicious (Perl)\x0d
Host: stream.watsonplatform.net\x0d
HTTP/1.1 400 Bad Request\x0d
X-Backside-Transport: FAIL FAIL\x0d
Connection: Keep-Alive\x0d
Transfer-Encoding: chunked\x0d
X-Error-Cause: Zuul Error: Malformed Session ID Cookie\x0d
Content-Type: application/json\x0d
Date: Wed, 01 Jun 2016 19:41:26 GMT\x0d
Server: -\x0d
X-Global-Transaction-ID: 237895544\x0d
X-DP-Watson-Tran-ID: stream-dp01-c0182762-b9fe-4533-acab-7fbeb02b63dd\x0d
The code is using a single instance of Mojo::UserAgent so the cookies are maintained on each request.
when using sessions you receive a SESSIONID cookie when creating the session, that cookie you need to send back to the service on every call you make after creating the session. Please note that the value of that cookie does not equal "session_id": "836cfc64b5856712b040a0b1b3bf4237", it is a longer alphanumeric string.
btw. why are you using sessions? what is your use case? maybe you could benefit from sessionless calls (simpler) or websockets (better for live use cases)
Dani
Using a trailing slash is the cause of this error. The interesting part is that the "start session" POST request with the trailing slash URL will succeed and return the correct JSON data. The next request to get the session status will fail. Not really a code problem. I also demonstrated the issue with curl.
my $ua = Mojo::UserAgent->new();
$ua->proxy->detect();
$ua->inactivity_timeout(0);
# THIS URL WORKS - no trailing slash
my $start_session_url = "https://${watson_username}:${watson_password}\#stream.watsonplatform.net/speech-to-text/api/v1/sessions";
# THIS URL DOES NOT WORK - with trailing slash
# my $start_session_url = "https://${watson_username}:${watson_password}\#stream.watsonplatform.net/speech-to-text/api/v1/sessions/";
my $session_tx = $ua->post($start_session_url);
my $response;
my $recognize_url;
if($response = $session_tx->success) {
print Dumper($response->json);
$recognize_url = $response->json->{recognize};
} else {
die "Failure to start session";
}
$recognize_url =~ s/https:\/\//https:\/\/${watson_username}:${watson_password}\#/;
# Malformed Cookie error happens here
my $status_tx = $ua->get($recognize_url);
if($response = $status_tx->success) {
print Dumper($response->json);
} else {
die "Failure to get session status";
}

LWP::UserAgent returns incomplete 2GB response message

I am using LWP::UserAgentto send request on a URL. But sometime in the response I am getting incomplete XML response.
Code
$args->{pua} = LWP::UserAgent->new();
$args->{header} = HTTP::Headers->new;
$args->{header}->header("Content-Type" => "text/xml", "SOAPAction" => $args->{soapaction});
$request = HTTP::Request->new( "POST", $args->{endpoint}, $args->{header}, $args->{xml});
$response = $args->{pua}->simple_request($request);
my $xmlResponse = $response->content;
In the $xmlResponse sometime I am getting incomplete response. Why is it happening?
ResponseHeader
Connection: close
Date: Tue, 19 May 2015 11:07:37 GMT
Server: nginx/1.6.2
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Type: text/xml;charset=ISO-8859-1
Client-Date: Tue, 19 May 2015 11:07:40 GMT
Client-Peer: 202.77.98.11:80
Client-Response-Num: 1
Client-Transfer-Encoding: chunked
X-Frame-Options: SAMEORIGIN
LWP may return incomplete response when it failed to read whole body because of the timeout or other read error. In this case $response->is_success will be true and $response->code will be 200, but response headers will contain special header called X-Died.
So you can check this header:
unless ($response->is_success) {
die "Response failed: ", $response->status_line;
}
if ($response->header('X-Died')) {
die "Response failed (internal): ", $response->header('X-Died');
}

Twitter api response unreadable

We have been using twitter api for a while now but suddenly it stopped working. Tracing it back it seems that the response from the MSXML2.ServerXMLHTTP request is unreadable by ASP vbscript.
Even a simple GET request to a page turns into invalid charactors. Opening https://api.twitter.com/oauth/request_token in a browser will show a string "Failed to validate oauth signature and token". When I try to get the same thing in ASP it returns unreadable data.
<% #LANGUAGE="VBSCRIPT" %>
<%
Set objXMLHTTP = Server.CreateObject("MSXML2.ServerXMLHTTP")
objXMLHTTP.open "GET", "https://api.twitter.com/oauth/request_token", false
objXMLHTTP.send ""
Response.Write "<pre>"
Response.Write objXMLHTTP.responseText
Response.Write "<hr>"
Response.Write objXMLHTTP.getAllResponseHeaders()
Response.Write "</pre>"
%>
output is:
?
------
Date: Thu, 06 Dec 2012 09:12:17 GMT
Status: 401 Unauthorized
X-MID: caa889032d29f5316a855dcadd748211ed4ee276
X-Frame-Options: SAMEORIGIN
Cache-Control: no-cache, no-store, must-revalidate, pre-check=0, post-check=0
Content-Type: text/html; charset=utf-8
Last-Modified: Thu, 06 Dec 2012 09:12:16 GMT
Pragma: no-cache
X-Transaction: dd71c8da0813a966
Expires: Tue, 31 Mar 1981 05:00:00 GMT
X-Runtime: 0.02056
Set-Cookie: k=10.36.75.125.1354785136971277; path=/; expires=Thu, 13-Dec-12 09:12:16 GMT; domain=.twitter.com
Set-Cookie: guest_id=v1%3A135478513698331395; domain=.twitter.com; path=/; expires=Sat, 06-Dec-2014 21:12:16 GMT
Set-Cookie: _twitter_sess=BAh7CDoPY3JlYXRlZF9hdGwrCFihfG87ASIKZmxhc2hJQzonQWN0aW9uQ29u%250AdHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7ADoHaWQiJTMx%250AMzI0YjhkNDc4YmQ4MDExMjlhNTI2NWU5OTAxNDVi--97206a42b05d8cb85fbd88ccd9ccb8aaca39ebef; domain=.twitter.com; path=/; HttpOnly
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 62
Server: tfe
the ? is infact a string with more charactors but cannot be handled because it contains a CHR(0).
Now I figured it might be because of the Content-Encoding: gzip, but even when sending an objXMLHTTP.setRequestHeader "Accept-Encoding", "none" (or any other format) it returns the same.
Anybody has any idea what I can do to solve this?
I have been looking at this for hours now and just after asking I find the awnser! Twitter API requires a user-agent to be sent a long with the request. So it was as simple as:
Set objXMLHTTP = Server.CreateObject("Msxml2.ServerXMLHTTP.6.0")
objXMLHTTP.open "GET", "https://api.twitter.com/oauth/request_token", false
objXMLHTTP.SetRequestHeader "User-Agent", "something"
objXMLHTTP.send()

adding a response header to 302 response using perl

i am trying to write a perl page that returns an http 302 response to a different location and adds a custom header to that response.
so my desired http response should be something like this:
HTTP/1.1 302 Moved
Date: Sun, 15 Apr 2012 10:59:02 GMT
Server: Apache
Location: http://www.google.com
Content-Length: 396
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1
CUSTOM_HEADER: CUSTOM_VALUE
i tried using CGI:
#!/bin/perl
use strict;
use APR::Request::Apache2;
my $r = shift;
$r->content_type('text/html; charset=utf-8');
$r->headers_out()->add("CUSTOM_HEADER", "CUSTOM_VALUE");
$r->headers_out()->add("Location", "http://www.google.com");
$r->status(302);
and i do get 302 response to google but no CUSTOM_HEADER. once i change the status to 200 by $r->status(200); i do get the CUSTOM_HEADER.
so whats up with this behavior ? how can i add my header to the 302 response ?
Use $r->err_headers_out->set or $r->err_headers_out->add
my $r = shift;
$r->content_type('text/html; charset=utf-8');
$r->err_headers_out->set(Location => "http://www.google.com");
$r->status(302);
You should use err_headers_out(). These will be printed even on errors and redirects.

How can I get both the GET and POST request params, on a POST request?

I'm creating a facebook app with a Perl backend. The problem is that since Facebook sends the request to my web app as a POST request I'm having a problem getting the GET parameters that were also part of the base URL for the application -- in effect I'm only getting the POST params from $CGI->Vars.
See CGI/MIXING POST AND URL PARAMETERS.
Short version: use $CGI->param() for post paramenters and $CGI->url_param() for query string parameters.
Dump CGI in favour of a better interface. Plack's param method returns GET and POST parameters mixed.
plackup -MPlack::Request -e 'sub {
my ($env) = #_;
my $r = Plack::Request->new($env);
return [200, ["Content-Type" => "text/plain"], [join "\n", $r->param("foo")]];
}'
> lwp-request -m POST -USe 'http://localhost:5000/fnord?foo=bar;baz=quux'
Please enter content (application/x-www-form-urlencoded) to be POSTed:
foo=123;baz=456
␄
POST http://localhost:5000/fnord?foo=bar;baz=quux
User-Agent: lwp-request/6.03 libwww-perl/6.03
Content-Length: 16
Content-Type: application/x-www-form-urlencoded
200 OK
Date: Thu, 27 Oct 2011 21:27:46 GMT
Server: HTTP::Server::PSGI
Content-Length: 7
Content-Type: text/plain
Client-Date: Thu, 27 Oct 2011 21:27:46 GMT
Client-Peer: 127.0.0.1:5000
Client-Response-Num: 1
bar
123
Just set $CGI::APPEND_QUERY_STRING = 1;