How do I use a Facebook signed_request in .NET?
asp.net-mvc, asp.net-mvc-5, c#, facebook-javascript-sdk, facebook-login
Solution
Yes, the signed_request can be used to verify that an incoming login request is genuine. If you're logging in a user with Javascript (via AJAX, for example) you can use the signed_request to ensure that the data isn't false.
According to Parsing the Signed Request, there are 3 major steps, however I'll be a little more specific.
- Take the signed_request string and split it into two strings. There is a period character (full stop) which is a delimiter.
- The first part of the string (the signature) is a hash of the second part.
- The second part contains some information about the user and the request (user ID, timestamp).
- The strings are in Base64, but cannot be decoded straight away.
- They are Base64-URL-encoded which means that `+` and `/` characters have been replaced with URL-friendly `-` and `_` characters. Replace `-` characters with `+` and `_` characters with `/`.
- The strings may not be fully Base64 padded. Base64 strings should be divisible by 4; pad the strings out as necessary.
- Hash the signature using HMAC (SHA256) using your app secret as the key and compare the result to the signature that was provided.
- Use the .NET class HMACSHA256.
1. Split and decode
Code
string response = ""; // the signed_request
string[] split = response.Split('.');
string signatureRaw = FixBase64String(split[0]);
string dataRaw = FixBase64String(split[1]);
// the decoded signature
byte[] signature = Convert.FromBase64String(signatureRaw);
byte[] dataBuffer = Convert.FromBase64String(dataRaw);
// JSON object
string data = Encoding.UTF8.GetString(dataBuffer);
FixBase64String()
static string FixBase64String(string str)
{
string result = str;
while (result.Length % 4 != 0)
{
result = result.PadRight(result.Length + 1, '=');
}
result = result.Replace("-", "+").Replace("_", "/");
return result;
}
2. Compare the hashes
byte[] appSecretBytes = Encoding.UTF8.GetBytes("my_app_secret_here");
HMAC hmac = new HMACSHA256(appSecretBytes);
byte[] expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(dataRaw));
bool areEqual = expectedHash.SequenceEqual(signature);
If `areEqual` is `true` then you can be sure that the signed request is valid and has not been tampered with (assuming your app secret is secure).
Remember to keep your app secret secure, otherwise malicious users can do bad things.
Problem
I'm using Facebook as a login provider for my web application (ASP.NET MVC). My login works similar to another StackOverflow post How to securely authorize a user via Facebook's Javascript SDK. I also share the user's concerns. The flow for my login is as Follows: 1. The user presses the login button. 2. The user must accept the app. 3. A javascript callback retrieves the response. ``` var authResponse = response.authResponse; ``` Object returned: ``` { accessToken: "...", expiresIn: 1234, signedRequest: "...", userID: "123456789" } ``` I've heard that I can used the `signed_request` to validate the user's request, but all the examples online are for PHP. How do I do this in .NET?