How to decode OAuth 2.0 for Canvas signed_request in C#?
Solution 1
The following should help you out..
(Note: The JObject reference is from JSON.NET available via http://james.newtonking.com/projects/json-net.aspx and http://json.codeplex.com/)
Namespaces used:
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json.Linq; // JSON.NET project
Code:
public Dictionary<string,string> DecodePayload(string payload)
{
var encoding = new UTF8Encoding();
var decodedJson = payload.Replace("=", string.Empty).Replace('-', '+').Replace('_', '/');
var base64JsonArray = Convert.FromBase64String(decodedJson.PadRight(decodedJson.Length + (4 - decodedJson.Length % 4) % 4, '='));
var json = encoding.GetString(base64JsonArray);
var jObject = JObject.Parse(json);
var parameters = new Dictionary<string, string>();
parameters.Add("user_id", (string)jObject["user_id"] ?? "");
parameters.Add("oauth_token", (string)jObject["oauth_token"] ?? "");
var expires = ((long?) jObject["expires"] ?? 0);
parameters.Add("expires", expires > 0 ? expires.ToString() : "") ;
parameters.Add("profile_id", (string)jObject["profile_id"] ?? "");
return parameters;
}
It is what I'm using in FaceSharp.. hope it helps
Solution 2
Same code but without Json.NET dependency:
public IDictionary<string, object> DecodePayload(string payload)
{
string base64 = payload.PadRight(payload.Length + (4 - payload.Length % 4) % 4, '=')
.Replace('-', '+').Replace('_', '/');
string json = Encoding.UTF8.GetString(Convert.FromBase64String(base64));
return (IDictionary<string, object>)new JavaScriptSerializer().DeserializeObject(json);
}
You can use it like this:
public ActionResult Index()
{
var dict = DecodePayload(Request["signed_request"].Split('.')[1]);
return Content("Access Token: " + (string)dict["oauth_token"]);
}
Solution 3
Sorry, bit of a StackOverflow noob, but for anyone trying to use JohnK's method to decode, it works brilliantly, just a couple of implementation tips for anyone like me and the others with the base64 encoding issue....
The Json reference is also available from nuGet
Install-Package Newtonsoft.Json
http://developers.facebook.com/docs/guides/canvas/#auth explains the ["signed_request"] element in more detail, but put simply, when Facebook posts back (in my case after a user registration request), you can get the data from the post, but the string is in TWO PARTS, separated by a '.' - As such, trying to decode ["signed_request"] will fail as '.' isn't a Base64 char. The first part is the signature to allow you to validate that the post came from Facebook (only us and them know the sig to decode) and the second is the payload.
So, I got this to work with the following code (in a MVC controller), source is a Facebook registration button....
<fb:registration fields="name,email" redirect-uri="http://dev.devurlgoeshere.co.uk/Account/Register" width="530">
</fb:registration>
and then the Controller code responds to the registration request
[HttpPost]
public ActionResult Register(object postData )
{
string requestData = Request.Form["signed_request"];
string[] splitPayload = requestData.Split('.');
string sig = splitPayload[0];
string payload = splitPayload[1];
var decodedObj = DecodePayload(payload);
// get the items from the decodedObject
string userFacebookID = decodedObj["user_id"];
// now do what you want with their FacebookID
return View();
}
hope this helps someone, and sorry if this should have been edit/feedback or whatever...
Solution 4
Check out the Facebook .Net SDK on Codeplex http://facebooksdk.codeplex.com. It will handle all the 'dirty work' for you. For example, I could call the following code either from a controller action or on Page_Load.
FacebookApp app = new FacebookApp();
string accessToken = app.Session.AccessToken;
long userId = app.UserId;
Thats it. You don't really need to worry about how facebook is returning the data to you or decoding it. The SDK handles all that for you.
Solution 5
i have change the DecodePayload by this and it work fine for me:
public Dictionary<string, string> DecodePayload(string payload)
{
//Remove the bad part of signed_request
//Begin
string[] sB64String = payload.Split('.');
payload = payload.Replace((sB64String[0] + "."), string.Empty);
//End
var encoding = new UTF8Encoding();
var decodedJson = payload.Replace("=", string.Empty).Replace('-', '+').Replace('_', '/');
var base64JsonArray = Convert.FromBase64String(decodedJson.PadRight(decodedJson.Length + (4 - decodedJson.Length % 4) % 4, '='));
var json = encoding.GetString(base64JsonArray);
var jObject = JObject.Parse(json);
var parameters = new Dictionary<string, string>();
parameters.Add("user_id", (string)jObject["user_id"] ?? "");
parameters.Add("oauth_token", (string)jObject["oauth_token"] ?? "");
var expires = ((long?)jObject["expires"] ?? 0);
parameters.Add("expires", expires > 0 ? expires.ToString() : "");
parameters.Add("profile_id", (string)jObject["profile_id"] ?? "");
return parameters;
}
Related videos on Youtube
user330468
Updated on April 30, 2022Comments
-
user330468 about 2 years
I'm able to successfully validate the signed request for a Facebook canvas app using the example here, but I'm unable to decode the payload. The Facebook documentation states that the 2nd parameter in signed_request is a base64url encoded JSON object. In PHP the payload is decoded using json_decode:
$data = json_decode(base64_url_decode($payload), true);
What is the equivalent in C#?
-
Romhein over 13 yearsHave you tried to use the Facebook C# SDK: github.com/facebook/csharp-sdk?
-
Nate Totten over 13 yearsThe Facebook C# SDK on github does not handle anything with authentication, it only does api requests.
-
-
John K over 13 years+1 Very helpful. I updated the answer with namespaces and reference to the JSON library used (in case the FaceSharp software isn't installed - it likely provides the JSON.NET library as part of itself.)
-
Pit Digger almost 13 yearsWhy not to do payload = sB64String[1]; instead of payload = payload.Replace((sB64String[0] + "."), string.Empty);
-
AyKarsi over 12 yearsFacebookApp app = new FacebookApp(); is now FacebookApp app = new FacebookApp(); I don't see anyway to get the userId without calling app.Get("me")..
-
IDIR Samir over 12 yearsYou didn't explain how the SDK decodes the signed_request :( I am setting up a Deauthorize() action to handle signed_request which is a POST by Facebook to my action with the parameter "signed_request" as a string. I want to decode it to get the user_id
-
Alexa Adrian over 12 yearsdict["oauth_token"] - is no longer a key: there is 'code' one, is this what I should use?
-
rboarman almost 12 yearsThis code does not work at the moment. See Bosshog's answer below for a working version.
-
Prakash almost 6 yearsThanks @Pavel, your code worked for decoding the payload.
-
Prakash almost 6 years@Pavel - Now, I am working on the "Workplace of Facebook". In workplace also, we will have the App. I am able to get the signed_request when the Workplace app is uninstalled. I can decode the payload but I am not able to validate the signature.