Update 2017!
The issue I had when I posted the original question has got nothing to do with the recent changes Facebook made when they forced everyone to version 2.3 of their API. For a solution to that specific problem, see sammy34's answer below. Version 2.3 of the /oauth/access_token endpoint now returns JSON instead of form-encoded values
For historical reasons, here's my original question/issue:
I've got an MVC5 Web application which is using the built-in support for authentication via Facebook and Google. When we built this app a few months ago, we followed this tutorial: http://www.asp.net/mvc/tutorials/mvc-5/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on and everything worked great.
Now, all of a sudden, the Facebook authentication has just stopped working alltogether. The Google authentication still works great.
Description of the problem: We click the link to connect using Facebook, we are redirected to Facebook where we are prompted if we wan't to allow our Facebook app access to our profile. When we click "OK" we are redirected back to our site, but instead of being logged in we simply end up at the login screen.
I've gone through this process in debug mode and I've got this ActionResult in my account controller as per the tutorial mentioned above:
// GET: /Account/ExternalLoginCallback
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
............
When stepping through the code and upon returning from Facebook, the loginInfo object is always NULL, which causes the user to be redirected back to the login.
In order to understand what is actually happening behind the scenes, I installed Fiddler and monitored the HTTP traffic. What I disovered is that upon clicking "OK" at the Facebook permission dialog, Facebook redirects back to our application with this URL:
https://localhost/signin-facebook?code=<access-token>
This URL is not an actual file and probably handled by some controller/handler built into this OWIN framework I'm guessing. Most likely, it is connecting back to Facebook using the given code to query information about the user which is trying to login. Now, the problem is that instead of doing that, we are redirected to:
/Account/ExternalLoginCallback?error=access_denied
Which I'm sure is something Facebook is doing, that is, instead of giving us the user data, it's redirecting us back with this error message.
This causes the AuthenticationManager.GetExternalLoginInfoAsync();
to fail and always return NULL.
I'm completely out of ideas. As far as we know, we did not change anything on our end.
I've tried creating a new Facebook app, I've tried following the tutorial again but I always have the same problem.
Any ideas welcome!
Update!
OK, this is driving me insane! I've now manually gone through the steps required to perform the authentication and everything works great when I do that. Why on earth is this not working when using the MVC5 Owin stuff?
This is what I did:
// Step 1 - Pasted this into a browser, this returns a code
https://www.facebook.com/dialog/oauth?response_type=code&client_id=619359858118523&redirect_uri=https%3A%2F%2Flocalhost%2Fsignin-facebook&scope=&state=u9R1m4iRI6Td4yACEgO99ETQw9NAos06bZWilJxJrXRn1rh4KEQhfuEVAq52UPnUif-lEHgayyWrsrdlW6t3ghLD8iFGX5S2iUBHotyTqCCQ9lx2Nl091pHPIw1N0JV23sc4wYfOs2YU5smyw9MGhcEuinvTAEql2QhBowR62FfU6PY4lA6m8pD3odI5MwBYOMor3eMLu2qnpEk0GekbtTVWgQnKnH6t1UcC6KcNXYY
I was redirected back to localhost (which I had shut down at this point to avoid being redirected immediately away). The URL I was redirected to is this:
https://localhost/signin-facebook?code=<code-received-removed-for-obvious-reasons>
Now, I grabbed the code I got and used it in the URL below:
// Step 2 - opened this URL in a browser, and successfully retrieved an access token
https://graph.facebook.com/oauth/access_token?client_id=619359858118523&redirect_uri=https://localhost/signin-facebook&client_secret=<client-secret>&code=<code-from-step-1>
// Step 3 - Now I'm able to query the facebook graph using the access token from step 2!
https://graph.facebook.com/me?access_token=<access-token-from-step-2>
No errors, everything works great! Then why the hell is this not working when using the MVC5 Owin stuff? There's obviously something wrong with the OWin implementation.
See Question&Answers more detail:
os