ASP.NET MVC5 OWIN Facebook Authentication Suddenly Not Working

2017 update!

The problem that I encountered when I posted the original question has nothing to do with the recent changes made by Facebook when they forced everyone to version 2.3 of their API. To solve this particular problem, see sammy34 answers below . Version 2.3 of the endpoint / oauth / access _token now returns JSON instead of formatted values

For historical reasons, here is my original question / question:

I have an MVC5 web application that uses native authentication support through Facebook and Google. When we built this application a few months ago, we followed this guide: 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 fine.

Now, all of a sudden, Facebook authentication just stopped working all together. Google Authentication still works great.

Description of the problem: we click on the link to connect using Facebook, we are redirected to Facebook, where we will be asked if we do not allow our Facebook application to access our profile. When we click "OK", we are redirected back to our website, but instead of logging in, we simply find ourselves on the login screen.

I went through this process in debug mode, and I have this ActionResult in my account controller according to the guide 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 navigating through the code and returning from Facebook, the loginInfo object is always NULL, which forces the user to be redirected back to the input.

To understand what is really going on behind the scenes, I installed Fiddler and monitored HTTP traffic. What I turned off is that after clicking “OK” in the Facebook permission dialog, Facebook redirects back to our application with this URL:

 https://localhost/signin-facebook?code=<access-token> 

This url is not the actual file and is probably being handled by some kind of controller / handler built into this OWIN structure, I guess. Most likely, he connects to Facebook using the specified code to request information about a user who is trying to log in. Now the problem is that instead we are redirected to:

 /Account/ExternalLoginCallback?error=access_denied 

I am sure that this is what Facebook does, that is, instead of giving us user data, it redirects us with this error message.

This causes the AuthenticationManager.GetExternalLoginInfoAsync(); to fail AuthenticationManager.GetExternalLoginInfoAsync(); and always returns NULL.

I have a lot of ideas. As far as we know, we have not changed anything on our part.

I tried to create a new application for Facebook, I tried it again, but I always had the same problem.

Any ideas are welcome!

Update

Ok, this is driving me crazy! Now I manually completed the steps necessary for authentication, and everything works fine when I do this. Why doesn't this work when using MVC5 Owin materials?

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 mistakes, everything works great! Then why the hell doesn’t it work when using the MVC5 Owin material? There is clearly something wrong with the OWin implementation.

+62
facebook asp.net-mvc-5 owin
Mar 12 '14 at 21:40
source share
12 answers

Good. I have a solution to the problem.

This is the code I had previously in the Startup.Auth.cs file:

 var x = new FacebookAuthenticationOptions(); //x.Scope.Add("email"); x.AppId = "1442725269277224"; x.AppSecret = "<secret>"; x.Provider = new FacebookAuthenticationProvider() { OnAuthenticated = async context => { //Get the access token from FB and store it in the database and //use FacebookC# SDK to get more information about the user context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken",context.AccessToken)); context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:name", context.Name)); context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:email", context.Email)); } }; x.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie; app.UseFacebookAuthentication(x); 

Notice how

 x.Scope.Add("email") 
Line

has been commented out, but still I request an email later in the OnAuthenticated handler? Yes it is. For some reason, this worked flawlessly for several weeks.

My solution was to simply uncomment x.Scope.Add ("email"); to make sure that the scope = email variable is present in the original Facebook request.

Now everything works as it was!

I don’t understand why this worked before it was. The only explanation I can come up with is that Facebook has changed something on their part.

+8
Mar 13 '14 at 22:34
source share

April 22, 2017 Patch : Version 3.1.0 of Microsoft.Owin packages is now available. *. If you have problems after changing the Facebook API from March 27, 2017, first try the updated NuGet packages. In my case, they solved the problem (working perfectly on our production systems).

Original answer:

In my case, I woke up on March 28, 2017 to find out that Facebook authentication Facebook suddenly stopped working. We have not changed anything in the application code.

It turned out that Facebook made a “forced update” of its graphical API from version 2.2 to 2.3 on March 27, 2017. One of the differences in these versions of the API seems to be that the Facebook /oauth/access_token does not respond longer with the body encoded in the form, but with JSON.

Now, in the Owin middleware, we find the protected override FacebookAuthenticationHandler.AuthenticateCoreAsync() method protected override FacebookAuthenticationHandler.AuthenticateCoreAsync() , which parses the response body as a form and then uses the access_token from the parsed form. Needless to say, the parsed form is empty, so the access_token also empty, causing an access_denied error access_denied chain.

To fix this quickly, we created a wrapper class for Oauth's Facebook response

 public class FacebookOauthResponse { public string access_token { get; set; } public string token_type { get; set; } public int expires_in { get; set; } } 

Then in OwinStart we added a custom return channel handler ...

  app.UseFacebookAuthentication(new FacebookAuthenticationOptions { AppId = "hidden", AppSecret = "hidden", BackchannelHttpHandler = new FacebookBackChannelHandler() }); 

... where the handler is defined as:

 public class FacebookBackChannelHandler : HttpClientHandler { protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { var result = await base.SendAsync(request, cancellationToken); if (!request.RequestUri.AbsolutePath.Contains("access_token")) return result; // For the access token we need to now deal with the fact that the response is now in JSON format, not form values. Owin looks for form values. var content = await result.Content.ReadAsStringAsync(); var facebookOauthResponse = JsonConvert.DeserializeObject<FacebookOauthResponse>(content); var outgoingQueryString = HttpUtility.ParseQueryString(string.Empty); outgoingQueryString.Add(nameof(facebookOauthResponse.access_token), facebookOauthResponse.access_token); outgoingQueryString.Add(nameof(facebookOauthResponse.expires_in), facebookOauthResponse.expires_in + string.Empty); outgoingQueryString.Add(nameof(facebookOauthResponse.token_type), facebookOauthResponse.token_type); var postdata = outgoingQueryString.ToString(); var modifiedResult = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(postdata) }; return modifiedResult; } } 

Basically, the handler simply creates a new HttpResponseMessage containing the equivalent information encoded in the form from the JSON response from Facebook. Please note that this code uses the popular Json.Net package.

With this custom handler, the problems seem to be fixed (although we are not yet deploying to prod :)).

Hope that someone else wakes up today with similar problems!

Also, if anyone has a cleaner solution, I would like to know!

+107
Mar 28 '17 at 7:37
source share

I noticed this problem yesterday. Facebook no longer supports Microsoft.Owin.Security.Facebook version 3.0.1. For me, this worked to install version 3.1.0. To upgrade to 3.1.0, run the Install-Package Microsoft.Owin.Security.Facebook command Install-Package Microsoft.Owin.Security.Facebook in the package manager console: https://www.nuget.org/packages/Microsoft.Owin.Security.Facebook

+24
Mar 28 '17 at 21:49
source share

I had the same issue with Google Authentication. The following worked for me: Changes in Google OAuth 2.0 and updates in the Google middleware for release 3.0.0 RC

+4
Aug 27 '14 at 21:16
source share

The latest Facebook update was 2015-02-09 ( https://www.nuget.org/packages/Microsoft.AspNet.WebPages.OAuth/ )

The latest version of the API at this point was version 2.2. Version 2.2 expired on March 25, 2017, which is a coincidence when the problem started. ( https://developers.facebook.com/docs/apps/changelog )

I assume that Facebook probably automatically updated the API, and now the MS OAUTH library cannot parse the new answer.

TL; DR: Microsoft WebPages OAuth library is deprecated (at least for FB) and you may have to find another solution

+3
Mar 28 '17 at 18:30
source share

I also had this problem, but it did not cause the scope setting. I had to understand this for a long time, but in the end I made sure that I installed the user registrar by setting the following in the OwinStartup.Configuration(IAppBuilder app) .

 app.SetLoggerFactory(new LoggerFactory()); // Note: LoggerFactory is my own custom ILoggerFactory 

This led to the following:

2014-05-31 21:14: 48,508 [8] ERROR
Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware
[(null)] - 0x00000000 - Authentication failed

System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: remote name cannot resolve: "graph.facebook.com" on
System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult)
in System.Net.Http.HttpClientHandler.GetResponseCallback (IAsyncResult ar) --- End of the internal stack of the exception stack --- on
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (Task
task) on
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (Task task) in System.Runtime.CompilerServices.TaskAwaiter`1.GetResult () on a Microsoft.Owin.Security.Facebook.FacebookAuthenticationHandler.d__0.ove auto

Based on the above call stack, I found that my Azure VM was unable to resolve graph.facebook.com. All I had to do to fix this was to run "ipconfig / registerdns" and everything was fixed ...

+2
Jun 01 '14 at 2:04 on
source share

The above solutions did not work for me. In the end, it seems to be related to the session. By waking up a session in a previous call, it will no longer return null from GetExternalLoginInfoAsync ()

  [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public ActionResult ExternalLogin(string provider, string returnUrl) { Session["WAKEUP"] = "NOW!"; // Request a redirect to the external login provider return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl })); } 

Like the OP, I had a third-party out, which worked fine for a long time, and then suddenly stopped. I believe this was due to changes made to my code when I configured the session to use Redis Cache on Azure.

+1
Nov 27 '14 at 23:50
source share

I also had this problem. I read many articles and topics for two days, including this. None of them worked for me. Facebook login worked fine before deployment, but after that it didn't work. I found out that something was wrong with my VPS connection, so I tried NextVPN on my VPS. But when I tried to log in through my computer, there was no new connection in NextVPN inside ProxiFire. Finally, installing OpenVPN on my VPS solved the problem.

0
Apr 28 '15 at 17:27
source share

Verify that you are receiving an external Internet connection from your application. If not, correct the external Internet connection. My problem was that I was using an EC2 AWS instance that suddenly stopped connecting to the Internet. It took me a while to realize that this is a problem.

0
May 19 '16 at 20:05
source share

I have been working on a solution for three days. And I just found it on github ( https://github.com/aspnet/AspNetKatana/issues/38#issuecomment-290400987 )

 var facebookOptions = new FacebookAuthenticationOptions() { AppId = "xxxxx", AppSecret = "xxxxx", }; // Set requested scope facebookOptions.Scope.Add("email"); facebookOptions.Scope.Add("public_profile"); // Set requested fields facebookOptions.Fields.Add("email"); facebookOptions.Fields.Add("first_name"); facebookOptions.Fields.Add("last_name"); facebookOptions.Provider = new FacebookAuthenticationProvider() { OnAuthenticated = (context) => { // Attach the access token if you need it later on for calls on behalf of the user context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken)); foreach (var claim in context.User) { //var claimType = string.Format("urn:facebook:{0}", claim.Key); var claimType = string.Format("{0}", claim.Key); string claimValue = claim.Value.ToString(); if (!context.Identity.HasClaim(claimType, claimValue)) context.Identity.AddClaim(new System.Security.Claims.Claim(claimType, claimValue, "XmlSchemaString", "Facebook")); } return Task.FromResult(0); } }; app.UseFacebookAuthentication(facebookOptions); 

And to get the values

 var info = await AuthenticationManager.GetExternalLoginInfoAsync(); if (info != null) { var firstName = info.ExternalIdentity.Claims.First(c => c.Type == "first_name").Value; var lastName = info.ExternalIdentity.Claims.First(c => c.Type == "last_name").Value; } 
0
Mar 30 '17 at 16:09
source share

It drove me crazy. Everything worked until I turned around in my intermediate environment. I used Microsoft.Owin.Security.Facebook version 3.0.1 from Nuget. Updated it to version 3.1.0 from Nuget, and I no longer received an access denied error ...

0
Apr 02 '17 at 9:12 on
source share

Despite the fact that I did everything sammy34 said, this did not work for me. I was at the same time with HaukurHaf : when I do apirequest manually in the browser, it works fine, but if I use my mvc application, GetExternalLoginInfoAsync() always returns null.

So, I changed a few lines to the sammy34 code , for example, to this comment: https://stackoverflow.com/a/212877/

Replaced by:

 if (!request.RequestUri.AbsolutePath.Contains("/oauth")) { request.RequestUri = new Uri(request.RequestUri.AbsoluteUri.Replace("?access_token", "&access_token")); } var result = await base.SendAsync(request, cancellationToken); if (!request.RequestUri.AbsolutePath.Contains("/oauth")) { return result; } 

Instead:

 var result = await base.SendAsync(request, cancellationToken); if (!request.RequestUri.AbsolutePath.Contains("access_token")) return result; 

And added this line to my FacebookAuthenticationOptions :

 UserInformationEndpoint = "https://graph.facebook.com/v2.8/me?fields=id,name,email,first_name,last_name,picture" 

and now it works. (fields and these parameters are optional)

Note. I have not updated Microsoft.Owin.Security.Facebook

0
Apr 6 '17 at 17:50
source share



All Articles