"Invalid signed request" exception when parsing fbsr cookie
description
I start saying that my webapp worked fine until yesterday, so something must have changed Facebook side.
I'm using Facebook C# SDK version 5.4.1.0.
My website is accessible at, say, http://my.website.com.
When a user visits the homepage, I use the FB Javascript library to login the user and authorize the application:
window.fbAsyncInit = function() {
FB.init({
appId: 'my-app-id',
channelUrl: '...',
status: true,
cookie: 'my.website.com',
xfbml: true,
oauth: true
});
};
(function(d) {
var js, id = 'facebook-jssdk'; if (d.getElementById(id)) { return; }
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/it_IT/all.js";
d.getElementsByTagName('head')[0].appendChild(js);
} (document));
...
at some point, after init has been executed:
FB.login(function(response) {
// reload page
}, { scope: 'user_birthday,email,publish_stream,publish_actions,offline_access' });
After FB.init is called, a first fbsr_my-app-id cookie is created for domain my.website.com, containing the oauth 2.0 signed request.
After FB.login is called, and user has authorized the app, another fbsr_my-app-id is created for domain .my.website.com (notice the dot at the beginning), containing another signed request. Another cookie is created too at this point, named fbm_my-app-id, for domain .my.website.com (notice the dot again), whose value is:
base_domain=my.website.com
When the page is reloaded after login, i call FacebookWebContext.IsAuthorized to check if my app has been authorized. That method parses the fbsr cookie in order to read and decode the signed request.
The problem is that the browser (i tried this with chrome 16 and firefox 9) sends both the fbsr cookies, without domain information. When i call IsAuthorized, and the method reads the fbsr cookie, .net returns the values of the two cookies concatenated with a comma, like "FIRSTFBSRCOOKIEVALUE,SECONDFBSRCOOKIEVALUE". So now the concatenated value contains two dots (one from each cookie value). The parsing method doesn't expect that, and throws an exception because the cookie value is malformed. The stack trace of the exception is as follows:
Type : System.InvalidOperationException, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Message : Invalid signed request.
Source : Facebook.Web
TryParse(System.String, System.String, Int32, Double, Boolean)
Stack Trace : at Facebook.FacebookSignedRequest.TryParse(String secret, String signedRequestValue, Int32 maxAge, Double currentTime, Boolean throws) in d:\prabir\Documents\Projects\facebooksdk\v5.4.1\Source\Facebook.Web\FacebookSignedRequest.cs:line 486
at Facebook.FacebookSignedRequest.Parse(String secret, String signedRequestValue) in d:\prabir\Documents\Projects\facebooksdk\v5.4.1\Source\Facebook.Web\FacebookSignedRequest.cs:line 253
at Facebook.FacebookSignedRequest.GetSignedRequest(String appId, String appSecret, HttpContextBase httpContext) in d:\prabir\Documents\Projects\facebooksdk\v5.4.1\Source\Facebook.Web\FacebookSignedRequest.cs:line 349
at Facebook.FacebookSession.GetSession(IFacebookApplication settings, HttpContextBase httpContext, FacebookSignedRequest signedRequest) in d:\prabir\Documents\Projects\facebooksdk\v5.4.1\Source\Facebook.Web\FacebookSession.cs:line 367
at Facebook.FacebookSession.GetSession(IFacebookApplication settings, HttpContextBase httpContext) in d:\prabir\Documents\Projects\facebooksdk\v5.4.1\Source\Facebook.Web\FacebookSession.cs:line 326
at Facebook.Web.FacebookWebContext.get_Session() in d:\prabir\Documents\Projects\facebooksdk\v5.4.1\Source\Facebook.Web\FacebookWebContext.cs:line 136
at Facebook.Web.FacebookWebContext.IsAuthenticated() in d:\prabir\Documents\Projects\facebooksdk\v5.4.1\Source\Facebook.Web\FacebookWebContext.cs:line 218
at Facebook.Web.FacebookWebContext.IsAuthorized(String[] permissions) in d:\prabir\Documents\Projects\facebooksdk\v5.4.1\Source\Facebook.Web\FacebookWebContext.cs:line 238
... my method calls
The exception is thrown inside Facebook.FacebookSignedRequest.TryParse, line 412:
string[] split = signedRequestValue.Split('.');
if (split.Length != 2)
{
// need to have exactly 2 parts
throw new InvalidOperationException(Properties.Resources.InvalidSignedRequest);
}
My facebook configuration in web.config is:
<facebookSettings appId = "my-app-id" appSecret = "my-app-secret" canvasPage="http://apps.facebook.com/my-app" canvasUrl="http://my.website.com:8091/" secureCanvasUrl="https://my.website.com:8091/" />
I use port 8091 for security reasons, maybe that can be the cause of FB creating two cookies.
I've read some blog posts saying that browsers, in case of multiple cookies with the same name, should always send just one of the cookies, although it's not specified how they should choose the cookie. Anyway i can confirm that the latest versions of both chrome and firefox send all the cookies even if they have the same name.
Maybe the key is in the fbm cookie, which tells which is domain of the right fbsr cookie; however, this information cannot be used server-side, because domain information of cookies is lost.
Please help me or share a possible solution if you've had this problem; I must ship a big fb application by the end of the month and suddenly its core part stopped working :(
Feel free to ask for additional details, bye
lorenzo