Skip to content

Google Auth- Asp.net core 3.1 #18858

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
kishorpise opened this issue Feb 6, 2020 · 50 comments
Closed

Google Auth- Asp.net core 3.1 #18858

kishorpise opened this issue Feb 6, 2020 · 50 comments
Labels
area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer
Milestone

Comments

@kishorpise
Copy link

For Social outh integration, I am trying some simple implementation. I am always getting
The auth state was missing or invalid. There is no much documentation available.

I read the post. #6486
it looks its out dated and not true. when I just add nuget reference, I have yellow mark on owin and others. and If I see release date of Microsoft.AspNetCore.Authentication.Google, It looks its released recently. how ever in my case I get only error without any hint for such a simple usecase.

Any hint will be appreciated.

Regards
Kishor

@mkArtakMSFT mkArtakMSFT added the area-identity Includes: Identity and providers label Feb 6, 2020
@blowdart blowdart added area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer and removed area-identity Includes: Identity and providers labels Feb 6, 2020
@blowdart
Copy link
Contributor

blowdart commented Feb 6, 2020

You're adding the wrong references. OWIN is not for Core. Follow the Core 2 or Core 3 instructions.

@kishorpise
Copy link
Author

Yes.. you are correct. That is what I also mentioned.

@blowdart
Copy link
Contributor

blowdart commented Feb 6, 2020

OK, what error are you getting? Can we see your startup class (remove any secrets first) and your csproj

@kishorpise
Copy link
Author

kishorpise commented Feb 6, 2020

Error what I am getting is -----The oauth state was missing or invalid.
Below is entire startup class. (asp.net core 3.1.1) and configuration in json.

 "ClientId": "XXXX",
    "ClientSecret": "XXXXXX",
    "CallbackPath": "/Account/GoogleCallBack",
    "project_id": "XXXXXXX",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs"

StartupClass

    public class Startup
    {

        ILoggerFactory loggerFactory;
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>(config =>
            {
                config.UseInMemoryDatabase("Memory");
            });

            // AddIdentity registers the services
            services.AddIdentity<IdentityUser, IdentityRole>(config =>
            {
                config.Password.RequiredLength = 4;
                config.Password.RequireDigit = false;
                config.Password.RequireNonAlphanumeric = false;
                config.Password.RequireUppercase = false;
                config.SignIn.RequireConfirmedEmail = true;
            })
                .AddEntityFrameworkStores<AppDbContext>()
                .AddDefaultTokenProviders();



            services.ConfigureApplicationCookie(config =>
            {
                config.Cookie.Name = "Identity.Cookie";
                config.LoginPath = "/Home/Index";

            });

            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton(Configuration);

            services.AddAuthentication(options =>
            {
                options.DefaultChallengeScheme =  CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = AzureADDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
            }

            ).AddCookie(config =>
            {
                config.Cookie.Name = "Identity.Cookie";
                config.LoginPath = "/Home/Index";

            }).


            AddGoogle("Google",

                options =>
                {
                    options.ClaimActions.Clear();
                    options.Scope.Add("profile");
                                       
                    options.Events = new OAuthEvents
                    {
                        OnRemoteFailure = context =>
                        {
                            context.HandleResponse();
//Here I get Error
                            var error = context.Failure.Message;
                            return Task.FromResult(0);
                        }
                    };

                    Configuration.Bind("google", options);
                }  )  ;

            services.AddCors(options =>
            {
                options.AddPolicy("AllowAll", p =>
                {
                    p.AllowAnyOrigin()
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
                });
            });

            services.AddAuthorization(options =>
            {

                options.AddPolicy("Cookies",
                    authBuilder =>
                    {
                        authBuilder.RequireRole("Administrators");
                    });

            });


            services.AddControllersWithViews();

            services.AddTransient<IEmailSender, EmailSender>();

        }




        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env,  ILoggerFactory loggerFactory)
        {

             
            this.loggerFactory = loggerFactory;
             

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();
             
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
                endpoints.MapControllerRoute(
                    name: "Api",
                    pattern: "{controller=Account}/{action?}");
            });
        }
    }
}

@blowdart
Copy link
Contributor

blowdart commented Feb 6, 2020

@HaoK @Tratcher

@blowdart blowdart added the area-identity Includes: Identity and providers label Feb 6, 2020
@blowdart
Copy link
Contributor

blowdart commented Feb 6, 2020

Oh what browser are you using?

@kishorpise
Copy link
Author

Chrome- Ideally this should not be problem. I just checked on IE. same issue.
Below is signature in controller.
[HttpGet]
[Route("[controller]/[action]")]
public IActionResult GoogleCallBack()
{.....

@blowdart
Copy link
Contributor

blowdart commented Feb 6, 2020

Ah ok that rules out out the samesite changes chrome made.

@analogrelay analogrelay removed the area-identity Includes: Identity and providers label Feb 6, 2020
@Tratcher
Copy link
Member

Tratcher commented Feb 6, 2020

You're trying to combine things in a confusing way. You already have AddIdentity so you don't need any of this code:

            services.AddAuthentication(options =>
            {
                options.DefaultChallengeScheme =  CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = AzureADDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
            }

            ).AddCookie(config =>
            {
                config.Cookie.Name = "Identity.Cookie";
                config.LoginPath = "/Home/Index";

            }).

So the simplified code looks like this:

            services.AddAuthentication()
                .AddGoogle(options =>
                {
                   // ...
                    Configuration.Bind("google", options);
                })  ;

See https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins?view=aspnetcore-3.1#configure-google-authentication

Also, CallbackPath does not refer to an MVC endpoint, it's a path that's handled internally by the auth middleware. The default is "/signin-google". Identity provides its own MVC callbacks in the Account controller that are called after the middleware completes.

Why are you trying to chang the token endpoint? Note Configuration.Bind isn't picking up that config line because the keys don't match.

That said, none of this explains your error message. Sharing a Fiddler trace would help track the affected fields.

@Tratcher Tratcher added the Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. label Feb 6, 2020
@Tratcher Tratcher removed their assignment Feb 6, 2020
@kishorpise
Copy link
Author

kishorpise commented Feb 7, 2020

Yes code is tried for getting solution for the resolution of error.
I have removed the block and tried same error is occurring. -Regarding fidler output
I can see, all responses are correct. (Redirect etc.) below is -(little modified request and response)

I can see state, redirect url, scope is correct.

GET /o/oauth2/v2/auth?response_type=code&client_id=XXXXXX&redirect_uri=https%3A%2F%2Flocalhost%3A44361%2FAccount%2FExternalLoginCallback&scope=profile&state=CfDJ8MlYFAXWQwBGo4IKoVfdgvOLbG8GxfxMyGCK6-uEj2yQRZ8OWsMCkdjaZKZ5J3twa7rpsGkdTio6Ey5884X5ySTxHHLIWSTQlpZxoRd7C4Tbv78CuItmssnZI_j_EC3oVNNe1DwpzSAZsUDwZQgaygKe3Bk7gp0hL9ITBtqpkXpKgn_cridNbAOaeZKtS7qhjMd_83RjYApXeixa-yWhKebBqOyK52TsRs__ZeiJuJclxu9M1EPIyadjsmv2R8gMjlvbaN8BwHNh5lvCmFev2y4 HTTP/1.1

I can see its response passed as

https://localhost:44361/Account/ExternalLoginCallback?state=CfDJ8MlYFAXWQwBGo4IKoVfdgvOLbG8GxfxMyGCK6-uEj2yQRZ8OWsMCkdjaZKZ5J3twa7rpsGkdTio6Ey5884X5ySTxHHLIWSTQlpZxoRd7C4Tbv78CuItmssnZI_j_EC3oVNNe1DwpzSAZsUDwZQgaygKe3Bk7gp0hL9ITBtqpkXpKgn_cridNbAOaeZKtS7qhjMd_83RjYApXeixa-yWhKebBqOyK52TsRs__ZeiJuJclxu9M1EPIyadjsmv2R8gMjlvbaN8BwHNh5lvCmFev2y4&code=4/wQEYFHjOZmI2BNBC0iB7rkOo-O94lecpVN9TUr5Ycg9Gvb1s8SggluvPzpGQv3bkxj0lAfzay9B1v5TeYfTAbEI&scope=profile+https://www.googleapis.com/auth/userinfo.profile
Content-Language

Again passed- another request -
GET /Account/ExternalLoginCallback?state=CfDJ8MlYFAXWQwBGo4IKoVfdgvOLbG8GxfxMyGCK6-uEj2yQRZ8OWsMCkdjaZKZ5J3twa7rpsGkdTio6Ey5884X5ySTxHHLIWSTQlpZxoRd7C4Tbv78CuItmssnZI_j_EC3oVNNe1DwpzSAZsUDwZQgaygKe3Bk7gp0hL9ITBtqpkXpKgn_cridNbAOaeZKtS7qhjMd_83RjYApXeixa-yWhKebBqOyK52TsRs__ZeiJuJclxu9M1EPIyadjsmv2R8gMjlvbaN8BwHNh5lvCmFev2y4&code=4/wQEYFHjOZmI2BNBC0iB7rkOo-O94lecpVN9TUr5Ycg9Gvb1s8SggluvPzpGQv3bkxj0lAfzay9B1v5TeYfTAbEI&scope=profile+https://www.googleapis.com/auth/userinfo.profile HTTP/1.1

I can see external cookie is set properly. and passed to next request. but in asp.net server. I am getting exception at

OnRemoteFailure = context =>
{
context.HandleResponse();
var error = context.Failure.Message;
return Task.FromResult(0);
}

Since this is not handled, page is always blank. Now my doubt is on controller. as I can see lot of param passed, but I think that is handled by middle ware, before it reaches to call back.

Below is my signature.

[HttpGet]
[Route("[controller]/[action]")]
public IActionResult ExternalLoginCallback()
{

my redirect url is correctly reflected and it looks. /signin-google has nothing to do with it.

Thanks and appreciate your help. Issue is not resolved yet.

Regards
Kishor

@ghost ghost added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. labels Feb 7, 2020
@Tratcher
Copy link
Member

Tratcher commented Feb 7, 2020

You've set CallbackPath to /Account/ExternalLoginCallback and that's interfering with Identity. Change CallbackPath back to /signin-google and let the middleware take care of it. The middleware will redirect to /Account/ExternalLoginCallback when it's done.

@kishorpise
Copy link
Author

Thanks for your hint. I take /signin-google is hardcoding, not a good practice... any way it worked. but now, I can see _signInManager.GetExternalLoginInfoAsync( ) is always returning null.
I checked in fidler, I can see /Account/ExternalLoginCallback has Identity.External cookie.

@Tratcher
Copy link
Member

Tratcher commented Feb 7, 2020

Thanks for your hint. I take /signin-google is hardcoding, not a good practice...

It doesn't have to be /signin-google, that's only the default. The requirement is that it not conflict with any other endpoint in your app.

but now, I can see _signInManager.GetExternalLoginInfoAsync( ) is always returning null.
I checked in fidler, I can see /Account/ExternalLoginCallback has Identity.External cookie.

Enable the debug application logs to find out why. Sharing an updated version of your Startup would also be a good sanity check.

@kishorpise
Copy link
Author

kishorpise commented Feb 7, 2020

There is something interesting going on. Below is truncated/tampered log.
-- No candidates found for the request path '/Account/signin-google' seems exception.

Log.--

Microsoft.AspNetCore.Mvc.ChallengeResult: Information: Executing ChallengeResult with authentication schemes (Google).
Microsoft.AspNetCore.Authentication.Google.GoogleHandler: Debug: HandleChallenge with Location: https://accounts.google.com/o/oauth2/v2/auth?XXXXXXXXXXXXXXXXXpath=/Account/signin-google; secure; samesite=none; httponly.
Microsoft.AspNetCore.Authentication.Google.GoogleHandler: Information: AuthenticationScheme: Google was challenged.
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Information: Executed action KWebServer.Controllers.AccountController.SignIn (KWebServer) in 221.1968ms
Microsoft.AspNetCore.Routing.EndpointMiddleware: Information: Executed endpoint 'KWebServer.Controllers.AccountController.SignIn (KWebServer)'
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished in 284.3989ms 302 
Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer: Debug: Connection ID "18158513712053354613" disconnecting.
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request starting HTTP/2.0 GET https://localhost:44361/Account/signin-google?state=XXXXXXXXXXXqM&scope=profile+https://www.googleapis.com/auth/userinfo.profile  
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware: Debug: The request path /Account/signin-google does not match a supported file type
Microsoft.AspNetCore.Routing.Matching.DfaMatcher: Debug: No candidates found for the request path '/Account/signin-google'
Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware: Debug: Request did not match any endpoints

Startup --

services.AddDbContext<AppDbContext>(config =>
            {
                config.UseInMemoryDatabase("Memory");
            });

            // AddIdentity registers the services
            services.AddIdentity<IdentityUser, IdentityRole>(config =>
            {

            })
                .AddEntityFrameworkStores<AppDbContext>()
                .AddDefaultTokenProviders();


            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton(Configuration);

            services.AddAuthentication().AddGoogle("Google", "Google",

                options =>
                {
                    Configuration.Bind("google", options);

                    options.ClaimActions.Clear();
                    options.SignInScheme = "Identity.External";
                    options.Scope.Clear();
                    options.Scope.Add("profile");
                    options.Events = new OAuthEvents
                    {
                        OnRemoteFailure = context =>
                        {
                            context.HandleResponse();
                            var error = context.Failure.Message;
                            return Task.FromResult(0);
                        }
                    };

                }

                )
            ;


            services.AddControllersWithViews();
            services.AddMvc();
            services.AddTransient<IEmailSender, EmailSender>();

@Tratcher
Copy link
Member

Tratcher commented Feb 9, 2020

Microsoft.AspNetCore.Routing.Matching.DfaMatcher: Debug: No candidates found for the request path '/Account/signin-google' That's fine, the auth middleware doesn't use endpoint routing, it does its own path matching later.

What was the response for the https://localhost:44361/Account/signin-google request?

@kishorpise
Copy link
Author

kishorpise commented Feb 10, 2020

  1. Response for the https://localhost:44361/Account/signin-google
    This localhost page can’t be found

  2. I added another provider, and I found same error.

Microsoft.AspNetCore.Authentication.Google.GoogleHandler: Information: Error from RemoteAuthentication: The oauth state was missing or invalid..

but the interesting point, in both provider, Google and AzureAD- exception is going to below block.
OnRemoteFailure - statement var error = context.Failure.Message;

 services.AddAuthentication().AddGoogle("Google", "Google",

                options =>
                {
                    Configuration.Bind("google", options);

                    options.SignInScheme = "Identity.External";
                    options.UserInformationEndpoint = "https://www.googleapis.com/oauth2/v1/certs";
                    options.Scope.Clear();
                    options.Scope.Add("email");

                    options.Events = new OAuthEvents
                    {
                        OnRemoteFailure = context =>
                        {
                            context.HandleResponse();
                            var error = context.Failure.Message;
                            return Task.FromResult(0);
                        }
                    };

                }

                ).AddAzureAD(options =>
              {
                  Configuration.Bind("AzureAd", options);

              })
            ;

@Tratcher
Copy link
Member

These partial code samples are getting hard to keep track of without context. Can you share a complete sample as a github repo?

@kishorpise
Copy link
Author

Hello,
I have created repo. Please download and confirm, I would delete later on and would update thread in detailed manner with solution

https://github.com/kishorpise/18858

Regards
Kishor

@Tratcher
Copy link
Member

What's with Startup1? It's not being used at the moment.

Do you actually want to map remote accounts to local accounts, or only use remote accounts like AAD and Google? This could be simplified if you do not need local accounts and can remove Identity. AddAzureAD doesn't combine well with Identity because it tries to mange its own cookie.

builder.AddOpenIdConnect(openIdConnectScheme, null, o => { });
builder.AddCookie(cookieScheme, null, o => { });

Remove this line, SignInScheme is set automatically:
https://github.com/kishorpise/18858/blob/de304be322d78275ddf9516abe5af3fc9d222c69/Startup.cs#L59
Why are you setting UserInformationEndpoint? That doesn't look like the right value.
https://github.com/kishorpise/18858/blob/de304be322d78275ddf9516abe5af3fc9d222c69/Startup.cs#L60

public static readonly string UserInformationEndpoint = "https://www.googleapis.com/oauth2/v2/userinfo";

Move UseAuthentication from here to here. It needs the routing endpoints to be calculated before it can pick up their policies.

Remove AAD's CallbackPath from config, or set it to /signin-aad. Having it set to /Account/ExternalLoginCallback conflicts with a later step in the login flow.
https://github.com/kishorpise/18858/blob/de304be322d78275ddf9516abe5af3fc9d222c69/appsettings.json#L18
https://github.com/kishorpise/18858/blob/de304be322d78275ddf9516abe5af3fc9d222c69/appsettings.Development.json#L17

The same for Google's CallbackPath.
https://github.com/kishorpise/18858/blob/de304be322d78275ddf9516abe5af3fc9d222c69/appsettings.json#L24
https://github.com/kishorpise/18858/blob/de304be322d78275ddf9516abe5af3fc9d222c69/appsettings.Development.json#L23

What's with all of these other config settings for Google? They're not being used for anything because the key names don't match.
https://github.com/kishorpise/18858/blob/de304be322d78275ddf9516abe5af3fc9d222c69/appsettings.json#L25-L28

@kishorpise
Copy link
Author

Thanks for your prompt reply. Answers for each and every point as below.
Objective is just get the email address from both provider in same application, -if possible name, and picture. rest would be managed within application. No mapping is needed.

  1. Startup1 was just backup. I removed and didn't get chance to delete before upload on repo.
  2. AddAzureAD doesn't combine well with Identity because it tries to mange its own cookie. there has to be option for modifying the cookie.

3)SignInScheme removed. This was placed after reading other blogs.
4) UserInformationEndpoint placed to get the info from google, after reading other blogs to see if that could be reason.
5) UseAuthentication moved to earlier place as suggested. this was tried as it signed in but info object was null.
6) for changing signin-aad and call back. I need to change registration for both provider. will make 2 call backs for each and let you know.

  1. Other key names are kept for future functionality, it will not cause any issue. will remove.

I am making changes and will get back to you.

Regards
Kishor.

@kishorpise
Copy link
Author

Dear,
as written to your first point-
Those logs don't match the code/config in https://github.com/kishorpise/18858/blob/master/Startup.cs. The errors imply you're still setting CallbackPath to conflicting values. I suggest "/signin-google" and "/signin-aad" without any Account prefix.

Entire code is shared with you... this is not production code and we change as we do debug. only constant is configuration values and .net core framework along with port number. rest every thing is temporary to fix the issue. If you are just commenting log is not matching I wanted to know does it work on your side, with these configured values ?
If removing controller Account//signin-aad and moving to /signin-aad I would call this as hard coding. I am confirming code does not work on 3.1 framework with latest nuget packages as per the documentation given. AddAzureAd ,AddAzureAD, AddOpenIdConnect and rest is all mess for simple one protocol with funny documentation.

If AddOpenIdConnect is to be used, we should remove from documentation, atleast from microsoft site, ->>
https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-aspnet-core-webapp

and are you sure as per the official documentation I have to use instead AddMicrosoftAccount of AddOpenIdConnect

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/microsoft-logins?view=aspnetcore-3.1

Thanks confusion.
Kishor

@Tratcher
Copy link
Member

If AddOpenIdConnect is to be used, we should remove from documentation, atleast from microsoft site

Yes, we have plans to replace AddAzureAD with something more flexible. It works for basic scenarios but it does not adapt well to other scenarios like yours.

and are you sure as per the official documentation I have to use instead AddMicrosoftAccount of AddOpenIdConnect

AddMicrosoftAccount provides OAuth support for Microsoft Accounts (e.g. outlook.com or hotmail.com addresses). AddOpenIdConnect is the general purpose auth component that AddAzureAD is built on.

Unfortunately I think you need more interactive support than we can provide through Github. Every indication so far is that this is a configuration issue and not a product issue so your next option is to contact Microsoft Support so they can help you set this up correctly.

@Tratcher Tratcher removed the Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. label Feb 20, 2020
@kishorpise
Copy link
Author

I read your thread carefully, I confirm this is product and documentation issue. AddAzureAD is going to be removed, so I should not be using this code, and there should not nuget updates for that.

https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-aspnet-core-webapp?view=aspnetcore-3.1

Sample link for download has netcoreapp2.1

Thanks for your suggestion to contact microsoft support.

Regards
Kishor

@kmate95
Copy link

kmate95 commented May 20, 2020

Sorry if off-topic but I just stumbled upon this thread.
I had a similar problem with the scaffolded Identity ExternalLogin.cshtml.cs (Asp.Net Core 3.1.3)
Where the provider logged in and called back with valid data but the process failed with invalid model error.
Like:

[14:57:29 INF] AuthenticationScheme: Identity.External signed in.
[14:57:29 INF] Request starting HTTP/2.0 GET https://localhost:44361/Account/ExternalLoginCallback
[14:57:29 INF] Error from RemoteAuthentication: The oauth state was missing or invalid.

The problem was that I had Nullable context enabled for my project and it produced a ValidationError when no returnUrl was provided with the login attempt. I changed (string returnUrl = null) to (string? returnUrl = null) on every action (and in all scaffolded Identity pages) and the error was gone.
The actual error happens in OnPostConfirmationAsync that's the first check for ModelState.IsValid.

@thorkia
Copy link

thorkia commented May 24, 2020

I am having a similar problem with the callback not being handled for google login.

Here is my sample code: https://github.com/thorkia/GoogleAuthTest

I can get it to work in Node using Passport - but I would prefer my backend to be C#

Here are the logs:
[16:01:40 INF] Request starting HTTP/2 GET https://localhost:5001/authentication/external/google-login
[16:01:40 INF] Executing endpoint 'GoogleAuthTest.WepAPI.Controllers.ExternalController.GoogleLogin (GoogleAuthTest.WepAPI)'
[16:01:40 INF] Route matched with {action = "GoogleLogin", controller = "External", page = ""}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult GoogleLogin(System.String) on controller GoogleAuthTest.WepAPI.Controllers.ExternalController (GoogleAuthTest.WepAPI).
[16:01:40 INF] Executing ChallengeResult with authentication schemes (["Google"]).
[16:01:40 INF] AuthenticationScheme: Google was challenged.
[16:01:40 INF] Executed action GoogleAuthTest.WepAPI.Controllers.ExternalController.GoogleLogin (GoogleAuthTest.WepAPI) in 38.7567ms
[16:01:40 INF] Executed endpoint 'GoogleAuthTest.WepAPI.Controllers.ExternalController.GoogleLogin (GoogleAuthTest.WepAPI)'
[16:01:40 INF] Request finished in 132.6938ms 302
[16:01:40 INF] Request starting HTTP/2 GET https://localhost:5001/google-login?response_type=code&client_id=myClientID&redirect_uri=https%3A%2F%2Flocalhost%3A5001%2Fsignin-google&scope=openid%20profile%20email&state=CfDJ8LpsmeNzTMhEjLSTbnpic6Qf19ppL5G0kA3uywH_0fNf-f3EHIFuJdRT-Cmug_5G4WRh7wMKY0tVlg6vUt_ajqj7hvfbX_s4kGvTVVQU3mciC0FwVQ5PXiXzdJiGdHss55t0M5FfYpsyopeiXo1iXhPgLJj9vKMzKaWKr1rZ9_3FQ7ecfHdwtu5cIqrkax8IHr7Y10JGsMrrr4kelPgRq2b7B26fWIPdKmwFk8ej4OI-4rQ0fxr53sH-hsrVeYzNaQ
[16:01:40 INF] Request finished in 4.0323ms 404

And in Chrome I see the following error:
No webpage was found for the web address: https://localhost:5001/google-login?response_type=code&client_id=myClientId&redirect_uri=https%3A%2F%2Flocalhost%3A5001%2Fsignin-google&scope=openid%20profile%20email&state=CfDJ8LpsmeNzTMhEjLSTbnpic6Qf19ppL5G0kA3uywH_0fNf-f3EHIFuJdRT-Cmug_5G4WRh7wMKY0tVlg6vUt_ajqj7hvfbX_s4kGvTVVQU3mciC0FwVQ5PXiXzdJiGdHss55t0M5FfYpsyopeiXo1iXhPgLJj9vKMzKaWKr1rZ9_3FQ7ecfHdwtu5cIqrkax8IHr7Y10JGsMrrr4kelPgRq2b7B26fWIPdKmwFk8ej4OI-4rQ0fxr53sH-hsrVeYzNaQ

@Tratcher
Copy link
Member

Tratcher commented May 24, 2020

Your AuthorizationEndpoint is wrong, it should point to Google's servers with this value:

public static readonly string AuthorizationEndpoint = "https://accounts.google.com/o/oauth2/v2/auth";

@thorkia
Copy link

thorkia commented May 24, 2020

@Tratcher That worked partially. Thank you. Now I am getting an error about cookie correlation:

[18:01:53 INF] Request starting HTTP/2 GET https://localhost:5001/authentication/external/google-login
[18:01:53 INF] Executing endpoint 'GoogleAuthTest.WepAPI.Controllers.ExternalController.GoogleLogin (GoogleAuthTest.WepAPI)'
[18:01:53 INF] Route matched with {action = "GoogleLogin", controller = "External", page = ""}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult GoogleLogin(System.String) on controller GoogleAuthTest.WepAPI.Controllers.ExternalController (GoogleAuthTest.WepAPI).
[18:01:53 INF] Executing ChallengeResult with authentication schemes (["Google"]).
[18:01:53 INF] AuthenticationScheme: Google was challenged.
[18:01:53 INF] Executed action GoogleAuthTest.WepAPI.Controllers.ExternalController.GoogleLogin (GoogleAuthTest.WepAPI) in 8.1016ms
[18:01:53 INF] Executed endpoint 'GoogleAuthTest.WepAPI.Controllers.ExternalController.GoogleLogin (GoogleAuthTest.WepAPI)'
[18:01:53 INF] Request finished in 30.3892ms 302
[18:01:53 INF] Request starting HTTP/2 GET https://localhost:5001/signin-google?state=CfDJ8LpsmeNzTMhEjLSTbnpic6RZFAADFv1dgmVdfCKESet5Pncoru1fIOlvUSBt1IVRwrVN0ZgKGNtqn9GGmEKIXbfBWRu_uizcWj-rXnS3KvvTjikXvrTI8Bx5agAV9a5iWiZYc2K8dI_YmfsFP26bSzlojv-ytpxT9hk2AZr7v6qmxrIvTjNTUkXw1uzsCC9lP4Spw0dmlqCRDTe7xPpAQImmLcm9rf4Q1VvtnOJuIUbKdgPUChqal0mZlaaeUf3Z5A&code=4%2F0AFjzwaVqSMQhPX4Bn0QZt_L-R4BeGRqB59Kkbga0vb58dj3KvNdaMT9GrZ5z4WO4LpVyQEPOxJTBMfz1s3G9qQ&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&authuser=0&prompt=none
[18:01:53 INF] AuthenticationScheme: APIScheme signed in.
[18:01:53 INF] Request finished in 156.4635ms 302
[18:01:53 INF] Request starting HTTP/2 GET https://localhost:5001/signin-google?state=CfDJ8LpsmeNzTMhEjLSTbnpic6RZFAADFv1dgmVdfCKESet5Pncoru1fIOlvUSBt1IVRwrVN0ZgKGNtqn9GGmEKIXbfBWRu_uizcWj-rXnS3KvvTjikXvrTI8Bx5agAV9a5iWiZYc2K8dI_YmfsFP26bSzlojv-ytpxT9hk2AZr7v6qmxrIvTjNTUkXw1uzsCC9lP4Spw0dmlqCRDTe7xPpAQImmLcm9rf4Q1VvtnOJuIUbKdgPUChqal0mZlaaeUf3Z5A&code=4%2F0AFjzwaVqSMQhPX4Bn0QZt_L-R4BeGRqB59Kkbga0vb58dj3KvNdaMT9GrZ5z4WO4LpVyQEPOxJTBMfz1s3G9qQ&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&authuser=0&prompt=none
[18:01:53 WRN] '.AspNetCore.Correlation.Google.B79ES2TpzMIbrVQ6aDocRyYMEDPTTCDW3VHA0gJYU30' cookie not found.
[18:01:53 INF] Error from RemoteAuthentication: Correlation failed..
[18:01:53 ERR] An unhandled exception has occurred while executing the request.
System.Exception: An error was encountered while handling the remote login.
---> System.Exception: Correlation failed.
--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
[18:01:54 INF] Request finished in 176.8483ms 500 text/html; charset=utf-8

@Tratcher
Copy link
Member

Sharing a Fiddler trace is the best way to troubleshoot cookie issues. Also, turning the logs up to debug level.

@thorkia
Copy link

thorkia commented May 24, 2020

@Tratcher I have attached the debug logs and the Fiddler trace. I removed my clientId from the items

10_Full.txt
debugLogs.txt

@Tratcher
Copy link
Member

Looks like you're stuck in a loop here...

https://github.com/thorkia/GoogleAuthTest/blob/ee6dd36788269fab3c104623315abbb114f26a46/GoogleAuthTest.WepAPI/Startup.cs#L59
Your redirect here is getting overwritten because you don't tell the framework that you handled the request. It does its default redirect back to the url that issued the initial challenge, which issues another challenge and around you go again.
ctx.HandleResponse()
Add this after your redirect above.

@Tratcher
Copy link
Member

Tratcher commented May 25, 2020

Also, that url format doesn't work here. Redirect("~/Index"); ~ is an MVC link generation specific feature. It should probably be just Redirect("/Index");

@thorkia
Copy link

thorkia commented May 25, 2020

@Tratcher That worked perfectly thanks!

I had tried the Redirect("~/Index"); as an alternative to the Redirect("/Index"); to see if that would work.

Adding the ctx.HandleResponse() was the perfect solution! Thanks!

I will update my Git sample. Feel free to use it as a simple sample!

@lagonell
Copy link

lagonell commented Aug 7, 2020

I have the same problem and I cannot find the solution, in google I found that the problem is due to chrome, see the following photo:

Error_Google

Does someone know how to solve this problem?

@kishorpise
Copy link
Author

kishorpise commented Aug 7, 2020 via email

@Tratcher
Copy link
Member

Tratcher commented Aug 7, 2020

I have the same problem and I cannot find the solution, in google I found that the problem is due to chrome, see the following photo:

Error_Google

Does someone know how to solve this problem?

You must access the site using https.

@lagonell
Copy link

lagonell commented Aug 8, 2020

Accessing with https does not solve the problem.

Error_Google_https

@Tratcher
Copy link
Member

Tratcher commented Aug 8, 2020

Can you share a fiddler trace file and your Startup config?

@lagonell
Copy link

I hope it can help

145_Full.txt

` public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

	public IConfiguration Configuration { get; }

	// This method gets called by the runtime. Use this method to add services to the container.
	public void ConfigureServices(IServiceCollection services)
	{
		services.AddSeo(Configuration);

		services.AddDbContext<ApplicationDbContext>(options =>
			options.UseSqlServer(
				Configuration.GetConnectionString("DefaultConnection")));

		services.AddIdentity<ApplicationUser, IdentityRole>(
			o =>
			{
				o.Password.RequireDigit = false;
				o.Password.RequireLowercase = false;
				o.Password.RequireNonAlphanumeric = false;
				o.User.RequireUniqueEmail = true;

			})
			.AddEntityFrameworkStores<ApplicationDbContext>()
			.AddErrorDescriber<SpanishIdentityErrorDescriber>()
			.AddDefaultTokenProviders();

		services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
			.AddCookie(options =>
			{
				options.Cookie.SameSite = SameSiteMode.None;
				options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
				options.Cookie.IsEssential = true;
			})
			.AddGoogle(googleOptions =>
			{
				googleOptions.ClientId = Configuration["Authentication:Google:ClientId"];
				googleOptions.ClientSecret = Configuration["Authentication:Google:ClientSecret"];
				googleOptions.Events.OnRemoteFailure = (context) =>
				{
					var error = context.Failure.Message;
					return Task.CompletedTask;
				};
			});

		services.AddDistributedMemoryCache();

		services.AddSession(options =>
		{
			options.Cookie.Name = ".QuinielaVirtual.Session";
			// Set a short timeout for easy testing.
			options.IdleTimeout = TimeSpan.FromSeconds(10);
			options.Cookie.HttpOnly = true;
			// Make the session cookie essential
			options.Cookie.IsEssential = true;
		});

		services.AddHttpClient<QuinielaVirtualService>();

		// Adding MediatR for Domain Events and Notifications
		//services.AddMediatR(typeof(Startup));

		services.AddTransient<IEmailSender, EmailSender>();
		services.AddTransient<ICipherService, CipherService>();
		services.AddTransient<IContentEmail, ContentEmail>();
		services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

		services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));

		services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");

		services.AddRazorPages();

		services.AddLanguageSetup();

		services.AddSignalR();

		services.AddDataProtection()
			.UseCryptographicAlgorithms(
				new AuthenticatedEncryptorConfiguration()
				{
					EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
					ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
				});
	}

	// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
	public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IWebHostEnvironment env)
	{
		app.AddCustomExceptionHandlingPipeline(loggerFactory, env);
		app.UseHttpsRedirection();

		FileExtensionContentTypeProvider contentTypes2 = new FileExtensionContentTypeProvider(new Dictionary<string, string>()
		{
			[".apk"] = "application/vnd.android.package-archive"
		});

		FileExtensionContentTypeProvider provider = new FileExtensionContentTypeProvider();
		provider.Mappings.Add(".apk", "application/vnd.android.package-archive");

		app.UseStaticFiles(new StaticFileOptions
		{
			ContentTypeProvider = provider,
			OnPrepareResponse = ctx =>
		   {
			   const int durationInSeconds = 60 * 60 * 24 * 365;
			   ctx.Context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.CacheControl] =
				   "public,max-age=" + durationInSeconds;
		   }
		});
		app.UseSession();
		app.UseCookiePolicy();
		app.UseRouting();
		app.UseAuthentication();
		app.UseAuthorization();

		app.UseEndpoints(endpoints =>
		{
			endpoints.MapRazorPages();
			endpoints.MapHub<Services.Chat>("/default");
			endpoints.MapHub<HubTChat>("/hubTChat");
		});
	}
}`

@Tratcher
Copy link
Member

The client isn't sending back the correlation cookie. Can you also share the fiddler trace for the prior request so we can see the cookies the server sent to the client?

@lagonell
Copy link

The truth is that I do not understand, what does that have to do with that I deactivate a flag from chrome and everything works correctly.

48_Full.txt

It is the same code deployed on the server.

This is the flag that you disabled and everything works:
Cookies without SameSite must be secure
If enabled, cookies without SameSite restrictions must also be Secure. If a cookie without SameSite restrictions is set without the Secure attribute, it will be rejected. This flag only has an effect if "SameSite by default cookies" is also enabled. – Mac, Windows, Linux, Chrome OS, Android

#cookies-without-same-site-must-be-secure

@Tratcher
Copy link
Member

Sorry, you need to go back one further. We need to see the request that redirected from android.quinielavirtual.com to accounts.google.com.

@lagonell
Copy link

Forgive me, here it is:

12_Full.txt

@lagonell
Copy link

This is from has the call from android.quinielavirtual.com and the following from google.

12_Full.txt

@Tratcher
Copy link
Member

Tratcher commented Aug 12, 2020

Set-Cookie: .AspNetCore.Correlation.Google.0HDdxeOq92yhxAG1ddlI2SAL--ggdgWZeL-6mxjh_0o=N; expires=Wed, 12 Aug 2020 21:01:02 GMT; path=/signin-google; samesite=none; httponly

The cookie is marked as samesite=none but doesn't have the secure attribute.

The redirect_uri=http%3A%2F%2Fandroid.quinielavirtual.com%2Fsignin-google is also using http. You must be using a TLS terminating proxy?

See our proxy docs https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-3.1. That will get your request scheme fixed up so your redirect_uri will be correct and your cookies will get the secure attribute.

@lagonell
Copy link

Man, you're a crack, it works.

Works

I am logged in. :)

@kishorpise
Copy link
Author

kishorpise commented Aug 12, 2020 via email

@ghost
Copy link

ghost commented Nov 12, 2020

Thank you for contacting us. Due to a lack of activity on this discussion issue we're closing it in an effort to keep our backlog clean. If you believe there is a concern related to the ASP.NET Core framework, which hasn't been addressed yet, please file a new issue.

This issue will be locked after 30 more days of inactivity. If you still wish to discuss this subject after then, please create a new issue!

@ghost ghost closed this as completed Nov 12, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 12, 2020
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-auth Includes: Authn, Authz, OAuth, OIDC, Bearer
Projects
None yet
Development

No branches or pull requests

7 participants