Vidhu
Vidhu

Reputation: 317

Login with google is not working in ASP.NET MVC on .NET 4.7x application

I am trying to integrate google authentication in my ASP.NET MVC application, but after Google verification, I am getting the below screen. It is not hitting the GoogleLoginCallback method. Instead of that, I am getting this screen:

[Google Authentication Response]

Here's the Javascript code I used for implementing this functionality:

<script type="text/javascript">
document.getElementById('googleLoginButton').onclick = function() {
    try {
        var clientId = '@GoogleClientId';
        var redirectUri = '@GoogleRedirectionUrl';

        // Create a state object with additional data
        var stateData = {
            returnUrl: window.location.pathname || "/Home/Index" // Default to home if no return URL is set
        };

        // Encode the state object as a JSON string and then base64 encode it
        var state = btoa(JSON.stringify(stateData));

        // URL-encode the state parameter to handle special characters
        var encodedState = encodeURIComponent(state);

        // Construct the Google OAuth URL with the encoded state parameter
        var googleAuthUrl = `https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&scope=openid%20email%20profile&state=${encodedState}`;

        // Redirect the user to Google's authentication page
        window.location.href = googleAuthUrl;
    } catch (error) {
        console.error("Error during Google authentication:", error);
        alert("An error occurred during Google authentication. Please try again.");
    }
};
</script>

My controller code:

[AllowAnonymous]
public async Task<ActionResult> GoogleLoginCallback(string state, string code, string scope, string authuser, string hd, string prompt)
{
    try
    {
        // Decode the state parameter
        var decodedState = HttpUtility.UrlDecode(state);
        var stateData = JsonConvert.DeserializeObject<dynamic>(Encoding.UTF8.GetString(Convert.FromBase64String(decodedState)));

        // Extract the returnUrl from the state object
        var returnUrl = stateData.returnUrl ?? "/Home/Index";

        // Step 1: Exchange the authorization code for an access token
        var client = new HttpClient();
        var tokenRequest = new Dictionary<string, string>
        {
            { "code", code },
            { "client_id", ConfigurationManager.AppSettings["GoogleClientId"] },
            { "client_secret", ConfigurationManager.AppSettings["GoogleClientSecret"] },
            { "redirect_uri", ConfigurationManager.AppSettings["GoogleRedirectionUrl"] },
            { "grant_type", "authorization_code" }
        };

        var tokenResponse = await client.PostAsync("https://oauth2.googleapis.com/token", new FormUrlEncodedContent(tokenRequest));
        var tokenResponseString = await tokenResponse.Content.ReadAsStringAsync();
        var tokenJson = JsonConvert.DeserializeObject<JObject>(tokenResponseString);
        var accessToken = tokenJson["access_token"]?.ToString();

        if (string.IsNullOrEmpty(accessToken))
        {
            throw new Exception("Unable to retrieve access token from Google.");
        }

        // Step 2: Use the access token to fetch user info from Google
        var userInfoResponse = await client.GetAsync($"https://www.googleapis.com/oauth2/v2/userinfo?access_token={accessToken}");
        var userInfoResponseString = await userInfoResponse.Content.ReadAsStringAsync();
        var userInfoJson = JsonConvert.DeserializeObject<JObject>(userInfoResponseString);

        var email = userInfoJson["email"]?.ToString();
        var name = userInfoJson["name"]?.ToString();

        // Step 3: Redirect to the return URL
        return Redirect(returnUrl);
    }
    catch (Exception ex)
    {
        // Log the exception for debugging
        System.Diagnostics.Debug.WriteLine($"Error in GoogleLoginCallback: {ex.Message}");
        System.Diagnostics.Debug.WriteLine($"Stack Trace: {ex.StackTrace}");

        // Redirect to an error page or the login page
        return RedirectToAction("Login");
    }
}

In the startup.cs file, I have this code:

    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/MLALogin/Login"), // Match your login path
            Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });

        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Configure Google Authentication
        app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
        {
            ClientId = ConfigurationManager.AppSettings["GoogleClientId"],
            ClientSecret = ConfigurationManager.AppSettings["GoogleClientSecret"],
            CallbackPath = new PathString("/MLALogin/GoogleLoginCallback") // Match your callback path
        });
    }

Here are the configurations made in RouteConfig.cs:

routes.MapRoute(
      name: "GoogleLoginCallback",
      url: "MLALogin/GoogleLoginCallback",  
      defaults: new { controller = "MLALogin", action = "GoogleLoginCallback", id = UrlParameter.Optional }
  ).RouteHandler = new DebugRouteHandler();
  
  routes.MapRoute(
      name: "MlaLogin",
      url: "{controller}/{action}/{id}",
      defaults: new { controller = "MLALogin", action = "Login", id = UrlParameter.Optional }
  ).RouteHandler = new DebugRouteHandler();

In my Google console, I have the following settings:

Google API console

It will be really helpful if anyone can help me to figure out the root cause for failing google authentication implementation.

Showing the token in url is also a security issue. Is there any way to prevent this?

Upvotes: 0

Views: 26

Answers (0)

Related Questions