I've made some changes in my ExternalLogin actions. I added a new field to my user table, for the first name, and I added code as to request the first name from facebook. It could be the reason why I am getting the error. I will not post the app secret for facebook external login here, but you know it is present in my code. When I register a new user with facebook it works and keeps the user logged in, and adds the user to the database, also gets the correct first name. However When I log off and attempt to log in with facebook, it forces me to register instead of logging me in (it redirects to the register with facebook page, saying "you have successfully authenticated with facebook. Please enter a user name for this site below and click the Register button to finish logging in.") Here is the code with the changes I made: Inside the Startup.Auth class:
app.UseFacebookAuthentication(new FacebookAuthenticationOptions()
{
AppId = "2737863089761791",
AppSecret = "",
BackchannelHttpHandler = new HttpClientHandler(),
UserInformationEndpoint = "https://graph.facebook.com/v2.8/me?fields=id,name,email,first_name,last_name",
Scope = { "email" },
Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = async context =>
{
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);
string claimValue = claim.Value.ToString();
if (!context.Identity.HasClaim(claimType, claimValue))
context.Identity.AddClaim(new System.Security.Claims.Claim(claimType, claimValue, "XmlSchemaString", "Facebook"));
}
}
}
});
Inside my ExternalLoginCallback action in AccountController:
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
var firstName = loginInfo.ExternalIdentity.Claims.First(c => c.Type == "urn:facebook:first_name").Value;
if (loginInfo == null)
{
return RedirectToAction("Login");
}
// Sign in the user with this external login provider if the user already has a login
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
case SignInStatus.Failure:
default:
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email, Name = firstName });
}
I figured it redirects me to the register page, because the line
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
returns failure inside ExternalLoginCallback and I don't know why. It must return success to get to the case:
case SignInStatus.Success
I had an error in my ExternalLoginConfirmation action, so i put some code in a try-catch block. It solved my problem, but I still don't know where the error was coming from:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
{
if (User.Identity.IsAuthenticated)
{
return RedirectToAction("Index", "Manage");
}
if (ModelState.IsValid)
{
// Get the information about the user from the external login provider
var info = await AuthenticationManager.GetExternalLoginInfoAsync();
if (info == null)
{
return View("ExternalLoginFailure");
}
var user = new ApplicationUser { UserName = model.Name, Email = model.Email , Name = model.Name};
var result = await UserManager.CreateAsync(user);
if (result.Succeeded)
{
try
{
var useraux = await UserManager.FindByEmailAsync(model.Email);
result = await UserManager.AddLoginAsync(useraux.Id, info.Login);
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
eve.Entry.Entity.GetType().Name, eve.Entry.State);
Response.Write("Object: " + eve.Entry.Entity.ToString());
Response.Write(" " +
"");
foreach (var ve in eve.ValidationErrors)
{
Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
ve.PropertyName, ve.ErrorMessage);
Response.Write(ve.ErrorMessage + "" +
"");
}
}
//throw;
}
if (result.Succeeded)
{
//--
//await StoreFacebookAuthToken(user);
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
return RedirectToLocal(returnUrl);
}
}
AddErrors(result);
}
ViewBag.ReturnUrl = returnUrl;
return View(model);
}