I\'m trying to setup integrated OWIN Facebook authentication in a new MVC 5 project in Visual Studio 2013. I have configured apps and keys as per this tutorial:
http
I had the same problem. I solve my problem just added app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
to the Startup.Auth.cs. I didn't have that in my Startup.Auth.cs so
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
always thrown me an Object reference not set to an instance of an object error. I figure that out by analyzing VS 2013 default template for MVC 5. So if you need more info on code structure or example take a look on VS 2013 MVC5 template.
Hongye Sun did all the heavy lifting in his answer above.
Here's some code that can be added to your controller class and be called in place of the troublesome AuthenticationManager.GetExternalLoginInfoAsync().
private async Task<ExternalLoginInfo> AuthenticationManager_GetExternalLoginInfoAsync_Workaround()
{
ExternalLoginInfo loginInfo = null;
var result = await AuthenticationManager.AuthenticateAsync(DefaultAuthenticationTypes.ExternalCookie);
if (result != null && result.Identity != null)
{
var idClaim = result.Identity.FindFirst(ClaimTypes.NameIdentifier);
if (idClaim != null)
{
loginInfo = new ExternalLoginInfo()
{
DefaultUserName = result.Identity.Name == null ? "" : result.Identity.Name.Replace(" ", ""),
Login = new UserLoginInfo(idClaim.Issuer, idClaim.Value)
};
}
}
return loginInfo;
}
This probably is a bug in identity OWIN extension code. I can't repro the issue as my facebook payload always returns a username field in json, which is missing from your fb response. I am not quite sure why it's not there.
The code in identity owin extension method doesn't have a null check for the identity's name claim which is same as the username field. We have filed a bug for it internally.
In order to workaround this issue, could you try replacing your ExternalLoginCallback method with following code:
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var result = await AuthenticationManager.AuthenticateAsync(DefaultAuthenticationTypes.ExternalCookie);
if (result == null || result.Identity == null)
{
return RedirectToAction("Login");
}
var idClaim = result.Identity.FindFirst(ClaimTypes.NameIdentifier);
if (idClaim == null)
{
return RedirectToAction("Login");
}
var login = new UserLoginInfo(idClaim.Issuer, idClaim.Value);
var name = result.Identity.Name == null ? "" : result.Identity.Name.Replace(" ", "");
// Sign in the user with this external login provider if the user already has a login
var user = await UserManager.FindAsync(login);
if (user != null)
{
await SignInAsync(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
else
{
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = name });
}
}
The code will set default user name as empty when there is no username back from facebook/google.
If your stack trace contains DotNetOpenAuth.AspNet then is the same bug as has apparently existed for two years in DotNetOpenAuth/DotNetOpenId.
NullReferenceException in DotNetOpenAuth
https://github.com/DotNetOpenAuth/DotNetOpenAuth/issues/317#issuecomment-29580565
The owner of those libraries indicate MS has abandoned them, although it looks from your defect like they are probably actually moved into MS code.
If so, does that mean OSS got buried into closed code?
Would love to see your stack trace.
I hadn't enabled the Google+ API and came back with access_denied when I looked at fiddler. Enabling the Google+ API sorted out the problem.