5

My question is very similar this but I guess I need to take it one step further.

Facebook says "The data is passed to your application as a signed request. The signed_request parameter is a simple way to make sure that the data you're receiving is the actual data sent by Facebook."

After a user has logged into my asp c# MVC site and clicked "Register", the redirect-url is http://site/account/register. At that point (the post to the account/register control), I would like to gather the user's information using the signed request so that I can register them with my site locally. I cannot figure out how to access the data facebook makes available.

$data = json_decode(base64_url_decode($payload), true);

What is the equivalent in C#? What type of variable/data is facebook passing in the post? And how do I access "$payload"?

[HttpPost]
    public ActionResult RegisterFacebook(RegisterFacebookModel model)
    {
        Facebook.FacebookSignedRequest sr = Facebook.FacebookSignedRequest.Parse("secret", model.signed_request);

        return View(model);
    }
Community
  • 1
  • 1
Josh
  • 1,876
  • 3
  • 21
  • 35

3 Answers3

8

Here is the code we used in the Facebook C# SDK. You don't need to do this manually if you use our sdk, but if you need to do it yourself here it is:

/// <summary>
/// Parses the signed request string.
/// </summary>
/// <param name="signedRequestValue">The encoded signed request value.</param>
/// <returns>The valid signed request.</returns>
internal protected FacebookSignedRequest ParseSignedRequest(string signedRequestValue)
{
    Contract.Requires(!String.IsNullOrEmpty(signedRequestValue));
    Contract.Requires(signedRequestValue.Contains("."), Properties.Resources.InvalidSignedRequest);

    string[] parts = signedRequestValue.Split('.');
    var encodedValue = parts[0];
    if (String.IsNullOrEmpty(encodedValue))
    {
        throw new InvalidOperationException(Properties.Resources.InvalidSignedRequest);
    }

    var sig = Base64UrlDecode(encodedValue);
    var payload = parts[1];

    using (var cryto = new System.Security.Cryptography.HMACSHA256(Encoding.UTF8.GetBytes(this.AppSecret)))
    {
        var hash = Convert.ToBase64String(cryto.ComputeHash(Encoding.UTF8.GetBytes(payload)));
        var hashDecoded = Base64UrlDecode(hash);
        if (hashDecoded != sig)
        {
            return null;
        }
    }

    var payloadJson = Encoding.UTF8.GetString(Convert.FromBase64String(Base64UrlDecode(payload)));
    var data = (IDictionary<string, object>)JsonSerializer.DeserializeObject(payloadJson);
    var signedRequest = new FacebookSignedRequest();
    foreach (var keyValue in data)
    {
        signedRequest.Dictionary.Add(keyValue.Key, keyValue.Value.ToString());
    }

    return signedRequest;
}

/// <summary>
/// Converts the base 64 url encoded string to standard base 64 encoding.
/// </summary>
/// <param name="encodedValue">The encoded value.</param>
/// <returns>The base 64 string.</returns>
private static string Base64UrlDecode(string encodedValue)
{
    Contract.Requires(!String.IsNullOrEmpty(encodedValue));

    encodedValue = encodedValue.Replace('+', '-').Replace('/', '_').Trim();
    int pad = encodedValue.Length % 4;
    if (pad > 0)
    {
        pad = 4 - pad;
    }

    encodedValue = encodedValue.PadRight(encodedValue.Length + pad, '=');
    return encodedValue;
}

You can find the full source code here: http://facebooksdk.codeplex.com/SourceControl/changeset/view/f8109846cba5#Source%2fFacebook%2fFacebookApp.cs

Nate Totten
  • 8,904
  • 1
  • 35
  • 41
  • Thank you for your response, Nathan. I've been short of time and haven't had a chance to test again yet, but what you showed makes sense. I'll take a look at the SDK as well. – Josh Jan 05 '11 at 01:37
  • I guess I still don't understand how to implement using this (or the SDK). Is the signed_request sent as a post to the redirect-uri in the fb:registration code? I'm using the js SDK for login/registration, but then trying to use the FacebookAPI that you referenced for deeper integration once the membership stuff is handled. I think if I could get past this point, I'd be good... I'm just hung up. I'm building a MVC project and trying to point the registration callback at an http post handler, but then need to decode the json object that fb is supposed to send. But I don't get anything back. – Josh Jan 09 '11 at 02:17
  • Nathan - can I ask a quick follow-up now that I am using the SDK - I see all of the parameters from the signed_request except the "Registration" parameters. (ie: "registration": { "name": "Paul Tarjan"... am I doing something wrong? When I post to the facebook test page I see them, but they aren't available after going through the SDK decode. "email": "fb@paulisageek.com", "location": { "name": "San Francisco, California", "id": 114952118516947 }, – Josh Feb 01 '11 at 22:33
  • 2
    i've got v5.0.8.0 of the Facebook C# SDK - and there is no `FacebookSignedRequest` class. Was it removed? – RPM1984 Apr 07 '11 at 23:40
1

Based on your comment, it looks like you're still looking for the response that FB is sending. I believe it it contained in the Form collection in the HttpContext Request object. So from the page you specify as the redirect, you should be able to pull it from:

HttpContext.Current.Request.Form("signed_request")

Hope that helps shed some light. I'm still learning as I go so this may not be the best solution.

thanks, Jason

Jason
  • 68
  • 5
  • Thanks, Jason. I'm working on an MVC project, so HttpContext isn't available in the controller environment, but I figured out how to combine the two answers and get it mostly working! Using the Facebook-SDK made it easy to process the returned "signed_request". – Josh Feb 01 '11 at 22:27
1

Here's how to do it using Facebook SDK

var parsedSignedRequest = FacebookSignedRequest.Parse(FacebookApplication.Current, signed_request);
Korayem
  • 12,108
  • 5
  • 69
  • 56
  • 4
    this is outdated if you're using Facebook SDK v6. It is now `var fb = new FacebookClient(); dynamic signedRequest = fb.ParseSignedRequest("app_secret", Request.Params["signed_request"]);` – Ian Davis Mar 28 '12 at 19:24