10

I've developed an ASPNET MVC 5 application using default Visual Studio 2015 Template and Google authentication. All works fine in the development environment but on real the call after external authentication AuthenticationManager.GetExternalLoginInfoAsync() sometimes returns null.

Normally it returns null on the central hours of the day (from 08:00 to 20:00) but I haven't found a pattern because sometimes works at that time. I've watched the developer console, but there are not a lot of requests (22 in the last 12 hours) and all are successful.

I've tried some solutions from other StackOverflow threads but they didn't work. Also, I can try them only on the night because is a personal project and then the connection is successful and I can't reproduce the issue.

The code is standard:

  • On Startup

    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context, user manager and signin manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
    
        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        // Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });            
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
    
        // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
        app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
    
        // Enables the application to remember the second login verification factor such as phone or email.
        // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
        // This is similar to the RememberMe option when you log in.
        app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
    
        var google = new GoogleOAuth2AuthenticationOptions()
        {
            ClientId = "xxxx",
            ClientSecret = "xxxx",
            Provider = new GoogleOAuth2AuthenticationProvider()
        };
        google.Scope.Add("email");
        app.UseGoogleAuthentication(google);
    }
    
  • On ExternalLoginCallback

    //
    // GET: /Account/ExternalLoginCallback
    [AllowAnonymous]
    public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
    {
        Log.Debug("AuthenticationManager.GetExternalLoginInfoAsync()");
        var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
        if (loginInfo == null)
        {
            Log.Error("AuthenticationManager.GetExternalLoginInfoAsync(): null");
            return RedirectToAction("Login");
        }
    ...
    

More info
I've created new Google credentials with another user and when I change the clientId and clientSecret, it works again... I don't know even when...

Yet more info
The problem is not on credentials, I "only" need to restart ASP.NET application to solve the issue, perhaps this new clue helps somebody to help me.

Not replicated
I've post the answer and it isn't in that OWIN's GetExternalLoginInfoAsync Always Returns null post, I've mentioned there the thread where I found the solution: ASP.NET_SessionId + OWIN Cookies do not send to browser

Marc
  • 1,359
  • 1
  • 15
  • 39
  • It's possible, but hard to test now (6 years after). The app is working fine in a production environment and now it's difficult to check if another solution solves the problem. – Marc Apr 18 '23 at 06:19

7 Answers7

19

Finally (I think that) I've found the solution after a week with no failed login. All thanks to this StackOverflow thread. My solution has been inserting the following line on AccountController.ExternalLogin action:

Session["Workaround"] = 0;

In the thread above (and links provided there) found a better explanation of the bug when mixing sessions and cookies of ASPNET MVC and OWIN component.

Full controller service code:

    //
    // POST: /Account/ExternalLogin
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult ExternalLogin(string provider, string returnUrl)
    {
        // https://stackoverflow.com/questions/20737578/asp-net-sessionid-owin-cookies-do-not-send-to-browser
        Session["Workaround"] = 0;
        // Request a redirect to the external login provider
        return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
    }
Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
Marc
  • 1,359
  • 1
  • 15
  • 39
  • Can you post your solution in full? – 3therk1ll Apr 04 '17 at 14:58
  • Rich C, I've updated the answer with full service code. It's only the base template code plus the tricky line. – Marc Apr 04 '17 at 15:33
  • 2
    The problem seems to be in owin - all you should know about it is to remember setting the cookie explicitly first before your service does it (owin). Solution Marc posted is mocking it up by setting the session (what ever named) to some value. – st35ly May 14 '17 at 09:09
8

I faced the Similar Issue with Visual Studio 2017 and .net MVC 5.2.4, Updating Nuget Microsoft.Owin.Security.Google to latest version which currently is 4.0.1 worked for me

Ikram Shah
  • 1,206
  • 1
  • 11
  • 12
1

Nothing worked for me tried all above combination...

But when updated all references dlls with latest on NUGET it worked like charm!!

1

After updating Microsoft.Owin.Security.Google version 4.1.1 (I'm using .NET framework 4.8) it works for me

Thai Tran
  • 11
  • 2
0

I updated to version 4.0.1 of the Microsoft.Owin.Security.Google package and I was having the same problem. I was getting null and access_denied. Turns out the problem was due to a space that I had copied over in the Client Secret. It took me 2 days and lots of unnecessary code changes to figure this out. I noticed that when you click copy (not just copy) and paste from Google, there is a space at the end of the Client Secret.

Dumber_Texan2
  • 840
  • 2
  • 12
  • 34
0

I had the same trouble going from version 4.0.1 to 4.1.1 of the Microsoft.Owin.Security.* packages.

This article SameSite in code for your ASP.net applications seems to offer some clues as to how to make set SameSite to avoid this error, but due to time pressure, I ended up having to go back to 4.0.1 and will have to revisit later.

didge
  • 316
  • 4
  • 14
0

I had the same issue today after upgrading Microsoft.Owin.Security.Facebook from 3.0.1 to 4.2.2. The issue happened because I had implemented the following workaround in the past because the email returned was blank at that moment Why new fb api 2.4 returns null email on MVC 5 with Identity and oauth 2? , however, now, after upgrade to 4.2.2 that workaround was breaking the functionality. For me, the fix was to remove the changes related to the workaround and now it is working as expected