I am trying to fix an intermittent issue when using Google as an external login provider.
When attempting to login, the user is redirected back to the login page rather than being authenticated.
The problem occurs on this line (line 55 of link below), GetExternalIdentityAsync returns null.
var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
The full code is:
[Authorize]
public abstract class GoogleAccountController<TUser> : Controller where TUser : Microsoft.AspNet.Identity.IUser
{
public IAuthenticationManager AuthenticationManager
{
get
{
return HttpContext.GetOwinContext().Authentication;
}
}
public abstract UserManager<TUser> UserManager { get; set; }
[AllowAnonymous]
[HttpGet]
[Route("login")]
public ActionResult Login(string returnUrl)
{
ViewData.Model = new LoginModel()
{
Message = TempData["message"] as string,
Providers = HttpContext.GetOwinContext().Authentication.GetExternalAuthenticationTypes(),
ReturnUrl = returnUrl
};
return View();
}
[AllowAnonymous]
[HttpPost]
[ValidateAntiForgeryToken]
[Route("login")]
public ActionResult Login(string provider, string returnUrl)
{
return new ChallengeResult(provider, Url.Action("Callback", "Account", new { ReturnUrl = returnUrl }));
}
[AllowAnonymous]
[Route("authenticate")]
public async Task<ActionResult> Callback(string returnUrl)
{
var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
if (externalIdentity == null)
{
return RedirectToAction("Login", new { ReturnUrl = returnUrl });
}
var emailAddress = externalIdentity.FindFirstValue(ClaimTypes.Email);
var user = await UserManager.FindByNameAsync(emailAddress);
if (user != null)
{
await SignInAsync(user, false);
return RedirectToLocal(returnUrl);
}
else
{
TempData.Add("message", string.Format("The account {0} is not approved.", emailAddress));
return RedirectToAction("Login", new { ReturnUrl = returnUrl });
}
}
[HttpPost]
[ValidateAntiForgeryToken]
[Route("logout")]
public ActionResult Logout(string returnUrl)
{
AuthenticationManager.SignOut();
return RedirectToLocal(returnUrl);
}
private async Task SignInAsync(TUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
var authenticationProperties = new AuthenticationProperties()
{
IsPersistent = isPersistent
};
AuthenticationManager.SignIn(authenticationProperties, identity);
}
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
protected override void Dispose(bool disposing)
{
if (disposing && UserManager != null)
{
UserManager.Dispose();
UserManager = null;
}
base.Dispose(disposing);
}
}
Which is also here.
This is very much an intermittent problem, and redeploying the app will often get it to work temporarily.
Looking in Fiddler I can see a call is made to sign-google just previous to the authenticate method in which it can't find the cookie.
The app uses the following code to initialize the google login
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/login")
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseGoogleAuthentication();
I have set the authentication mode to non in the web.config, and removed the forms authentication module.
<system.web>
<authentication mode="None" />
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<remove name="FormsAuthenticationModule" />
</modules>
</system.webServer>
The sites are hosted on Azure, some running on 1 instance, some 2. They have custom domains, although still fail on both custom domain and azurewebsites domain, and http / https.
Can anyone help with why this might be happening?
Update
Version 3.0 of Microsoft.Owin.Security.Google was released last night. Going to switch over and see if this fixes the issue.
https://www.nuget.org/packages/Microsoft.Owin.Security.Google