Receiving 400 Client Error from Google Reader API (specifically, user authorized edits/deletes) - google-reader

I've been trying to fix a google reader client for the iphone I wrote more than half a year ago, which broke after Google changed its authentication scheme for google reader in June. I've currently hit a roadblock with edit/delete functionality for items, feeds and folders...
www.google.com/reader/api/0/subscription/edit
www.google.com/reader/api/0/edit-tag
www.google.com/reader/api/0/mark-all-as-read
www.google.com/reader/api/0/disable-tag
www.google.com/reader/api/0/item/edit
www.google.com/reader/api/0/item/delete
Requests made to the above interfaces all result in 400 Bad Request errors. Checking the response heads for my requests, I see that the reason is a bad token.
"Cache-Control" = "no-cache, no-store,
max-age=0, must-revalidate";
"Content-Length" = 1334;
"Content-Type" = "text/html;
charset=UTF-8"; Date = "Thu, 25 Nov
2010 09:51:08 GMT"; Expires = "Fri, 01
Jan 1990 00:00:00 GMT"; Pragma =
"no-cache"; Server = GSE;
"X-Content-Type-Options" = nosniff;
"X-Frame-Options" = SAMEORIGIN;
"X-Reader-Google-Bad-Token" = true;
"X-Reader-Google-Version" = "521-000";
"X-Reader-User" =
05659401224324679732;
"X-Xss-Protection" = "1; mode=block";
This makes sense, as the above API are the only ones that require the token you get from
www.google.com/reader/api/0/token
Here's a sample of one of the tokens I'm using:
tpMLOEjtCjn2zzb6Gg2IYw
Now, prior to June the above functionality was working, so the my token acquirement must have been correct. I'm currently using the same endpoint and getting a response, so it seems to be ok, although the token I'm getting back seems suspiciously short, given how long the SID and auth tokens are (I can't recall whether the token was this short prior to June). Expiry is not a possibility, since I get the same error even when I log-in again and reacquire a new token. I've made sure that aren't any whitespaces in my token string, so it can't be that either.
Does anyone have any idea what I could be doing wrong? I haven't been able to find any other info elsewhere online regarding, except for an unanswered post on the same topic that speculated that an HSID string might be required along with the SID in the cookie.

Google no longer accepts the SID cookie. You now need to pass the Auth as an http header.
This answer from another question might help, Google Reader API?

Related

Cookie Persistence : cannot set expiry date

I am attempting to change an MVC web site that was storing some info in Session to store it in a cookie but am having some issues with the expiry of the cookie.
Scenario
While logging in to the site a cookie is created and added to the current HttpContext Response cookies collection. The code piece used to write the cookie is as follows :
HttpCookie userCredsCookie = _context.Response.Cookies.Get(Constants.Web.UserCredentialsCookieName) ?? new HttpCookie(Constants.Web.UserCredentialsCookieName);
userCredsCookie.HttpOnly = true;
userCredsCookie.Secure = true;
userCredsCookie.Value = user.ID.ToString();
userCredsCookie.Expires = DateTime.Now.AddMinutes(user.CompanySessionTimeout + user.TimezoneOffset);
_context.Response.Cookies.Add(userCredsCookie);
I have experimented with removal of the line that sets the expiry of the cookie and have found that the cookie is generated and stored at the client as expected.
When i inspect the response from the server using Fiddler i can see that the userCreds cookie is being returned :
Response sent 111 bytes of Cookie data:
Set-Cookie: UserCreds=e2ce8200-fb38-45b9-8aec-4d93e6640a84; expires=Mon, 09-Oct-2017 16:20:43 GMT; path=/; secure; HttpOnly
when the expiry is not set the response has :
Response sent 72 bytes of Cookie data:
Set-Cookie: UserCreds=e2ce8200-fb38-45b9-8aec-4d93e6640a84; path=/; secure; HttpOnly
As long as the expiry is not set, the cookie is accepted by the browser and sent on the subsequent requests made from the browser.
It feels like the problem is due to the format of the date in the response but i cannot find anything to allow me to change that format.
Any help would be greatly appreciated.
Regards
Monty
Update - Possible cause located
I have found that the problem i am having is to do with timing. It seems that my dev pc may be processing the responses from the ajax call that is setting the cookie too fast (??? is that even possible ???).
While i was debugging the front end code to ensure things look fine from that perspective i found that by placing a break point just before the line which was setting the window.location to a url that is in the result of the ajax call, the subsequent call was made with the cookie being on the request.
Perhaps, by causing the processing of the callback to pause, gave the system time to persist the cookie. I assume the process of persisting a cookie is to do a validation check then store the data. That would mean that it takes a little longer to validate the cookie when their is an expiry date set. Perhaps the reason why a cookie with no expiry set was persisting but ones with an expiry were not was cause the load of a new url interrupted the process, thus causing the cookie to not get stored.
By adding a 1 millisecond delay (yep, just 1 millisecond) in the success handler of the ajax call i was able to successfully have the cookie persisted to the browser and included in the call made to load a return url that is in the ajax response.
Does this sound even possible?
try with this code
int result = Convert.ToInt32(user.CompanySessionTimeout.ToString()) + Convert.ToInt32(user.TimezoneOffset)
and then pass
userCredsCookie.Expires = DateTime.Now.AddMinutes(result);

AccessToken for Windows Push Notifications returns Bad Request 400

PLEASE HELP!! Can't figure out why this simple code given by MSDN doesn't work....
I am using the following code in GetAccessToken() as given in the this MSDN article to get the access token to be used in windows notifications, but it returns "Bad Request 400"
PACKAGE_SECURITY_IDENTIFIER, CLIENT_SECRET are the values obtained when the app was registered with the Windows Store Dashboard
string urlEncodedSid = HttpUtility.UrlEncode(PACKAGE_SECURITY_IDENTIFIER);
string urlEncodedSecret = HttpUtility.UrlEncode(CLIENT_SECRET);
string body = String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=notify.windows.com", urlEncodedSid, urlEncodedSecret);
string response;
using (WebClient client = new WebClient())
{
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
response = client.UploadString("https://login.live.com/accesstoken.srf", body);
}
Any help would be highly appreciated.......
I suspect the problem has to do with either an incorrect package identifier, and / or incorrect client secret.
From the MSDN page Push notification service request and response headers:
RESPONSE DESCRIPTION
--------------- --------------------------
200 OK The request was successful.
400 Bad Request The authentication failed.
Update - I ran the code from the question, using FAKE credentials.
Here is the RAW HTTP request:
POST https://login.live.com/accesstoken.srf HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: login.live.com
Content-Length: 88
Expect: 100-continue
Connection: Keep-Alive
grant_type=client_credentials&client_id=test&client_secret=test&scope=notify.windows.com
Here is the server's RAW response:
HTTP/1.1 400 Bad Request
Cache-Control: no-store
Content-Length: 66
Content-Type: application/json
Server: Microsoft-IIS/7.5
X-WLID-Error: 0x80045A78
PPServer: PPV: 30 H: BAYIDSLGN2A055 V: 0
Date: Thu, 21 Mar 2013 12:34:19 GMT
Connection: close
{"error":"invalid_client","error_description":"Invalid client id"}
You will note that the response is a 400. There is also some json that indicates the type of error. In my case, the error is Invalid client id. You probably want to take a look at your response - it will give you an indication of what happened.
I used Fiddler to debug the request/ response.
I found the reason for the error response. In fact it is the wrong PACKAGE_SECURITY_IDENTIFIER and CLIENT_SECRET.
DO NOT type the values. Because associated ASCII values differ. Therefore it is always better to copy and paste directly.
You will probably will get the access token with the simple code snippet.
Cheers
If you're using the new HttpClient API and you're sure you've copied and pasted the SID/secret values correct, you might be experiencing this issue because of encoding, provided you're using the FormUrlEncodedContent class as the content of your POST operation.
Contrary to the examples in the MSDN documentation, you don't want to URL encode the SID and secret values before adding them to the KeyValuePair collection. This is because encoding is implied by the FormUrlEncodedContent class, though I'm not seeing any documentation for this behavior. Hopefully this saves someone some time because I've been wrestling with this all night...

Is it possible to set a cookie during a redirect in ASP.NET?

I am using ASP.NET. I either add or set a cookie (depending on whether the HttpRequest contains a cookie with specified key), and immediately afterward call Response.Redirect. The cookie is not set. Is this correct behavior? Is there something mutually exclusive about setting a cookie during an http response with a 302 status code?
Here's the source:
if (context.HttpContext.Request.Browser.Cookies)
{
var cookies = context.HttpContext.Request.Cookies;
var stateCookie = new HttpCookie(SR.session, clientState.SessionId.ToString());
if (cookies.AllKeys.Contains(SR.session))
{
context.HttpContext.Response.Cookies.Set(stateCookie);
}
else
{
context.HttpContext.Response.Cookies.Add(stateCookie);
}
}
Here are the Response headers
X-AspNetMvc-Version - 2.0
Connection - Close
Cache-Control - private
Content-Type - text/html
Date - Sun, 20 Mar 2011 03:48:04 GMT
Location - http://localhost:3599/Home/Redirected
Server - ASP.NET Development Server/9.0.0.0
X-AspNet-Version - 2.0.50727
After googling a bit it seems that yes, there can be problems with setting the cookie in the redirect response as it may be ignored by a few browsers. (It may make some sense, as the response is really telling the client to ignore the resource and get some other resource instead).
This has been discussed here already: Sending browser cookies during a 302 redirect
So I would change the architecture in a way that allows the page being redirected to to set the cookie.

What's the rationale behind the HTTP Date header?

I have read RFC 2616, but still I wonder, what the Date field is for. There is the Last-Modified field, that actually has a meaning besides just serving metadata, that is, for caching ('If-Modified-Since').
But what use has it to double the info in a separate Date header?
Per the spec, it is used in age calculations. If you don't know what time the server thinks it is, you won't be able to calculate the "age" of a resource. Here's the relevant text from the spec:
Summary of age calculation algorithm, when a cache receives a response:
age_value
is the value of Age: header received by the cache with
this response.
date_value
is the value of the origin server's Date: header
request_time
is the (local) time when the cache made the request
that resulted in this cached response
response_time
is the (local) time when the cache received the
response
now
is the current (local) time
apparent_age = max(0, response_time - date_value);
corrected_received_age = max(apparent_age, age_value);
response_delay = response_time - request_time;
corrected_initial_age = corrected_received_age + response_delay;
resident_time = now - response_time;
current_age = corrected_initial_age + resident_time;
The Date is needed only for a better work of Expires header:
Date: Mon, 26 Mar 2012 12:53:02 GMT
Expires: Wed, 25 Apr 2012 12:53:02 GMT
A server or a client may have an incorrect time so client (browser) tries to calculate max age of the resource freshness.
That was one of the reasons why the Cache-Control tag was introduced.
It uses seconds to expire instead of a fixed time.
I tested Chrome and Firefox and they are fine is response without Date header so it can be safely omitted unless you are still using obsolete Expires header. If the Date is missing it just assumed the same as client's time.
It's just insane that in spec the header is mandatory: the date formatting/parsing consumes CPU and network.
Please consider not to use the Date Header as it is on the list of the "Forbidden header names".
The following description from the MDN web docs might help:
A forbidden header name is the name of any HTTP header that cannot be modified programmatically; specifically, an HTTP request header name (in contrast with a Forbidden response header name).
Modifying such headers is forbidden because the user agent retains full control over them. Names starting with Sec- are reserved for creating new headers safe from APIs using Fetch that grant developers control over headers, such as XMLHttpRequest.
Forbidden header names start with Proxy- or Sec-, or are one of the following names:
Accept-Charset
List item
Accept-Encoding
Access-Control-Request-Headers
Access-Control-Request-Method
Connection
Content-Length
Cookie
Cookie2
Date
DNT
Expect
Host
Keep-Alive
Origin
Proxy-
Sec-
Referer
TE
Trailer
Transfer-Encoding
Upgrade
Via

Disabling client cache from Jetty server for REST requests

I have a REST Java server implemented with Jersey running on Jetty. It seems that certain browsers (IE7) internally caches all requests made to the server.
What I would like to do is to send a certain HTTP header in the response from the REST server indicating the browser that it shouldn't cache that response, and so will query the server again the next time it needs access to that resource.
Any ideas on how to configure Jersey/Jetty for this?
Or the only way to configure it is client-side?
response.setHeader("Pragma", "no-cache");
No, No. No!
The use of the pragma header to disabling client side caching is wrong, it's a request header and has zero effect on the response.
http://www.mnot.net/cache_docs/#PRAGMA
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.32
Also, setting Expires: 0 isn't correct, Expires should be a date, not a number of seconds, however this will work as an invalid http date is interpreted as "already expired"
http://www.mnot.net/cache_docs/#EXPIRES
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21
There's nothing you can do about rogue clients, but Jetty can send the appopriate HTTP headers. Try here for info on configuring the Last-Modified and Cache-Control headers.
On the server side you can try this if you have access to the response (you might be able to do it through filters).
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Expires", "0");
Another trick you can try on the client side is to add an superfluous argument to the url like "http://www.company.com/services/staff?id=xxx&requestTime="+(new Date()).getTime(); This way the url being request is different every time and it can't be cached.
#Dave Cheney: well, what I understand from http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 is that Cache-control makes sense for the request as well as for the response. And when the response is a cache-controled response, it's a specification for what the client (browser) should do with the resource (see next section, 14.9.1).
#all: Also, in section 14.21 of the same document it's specified that the Expires header set on 0 means 'invalid date' and can be ignored by the clients. And my tests with sending an expires date to 1 jan 1970 (timestamp 0) causes nothing but ignore from IE (and ff for that matter), which will still cache the response.
My solution was to send the current date for the Expires field, which is what the spec says.

Resources