Google Auth: "The oauth state was missing or invalid. Unknown location"
Asked Answered
V

2

1

I am trying to set up Google Auth on ASP.NET Core 3 and I get this error:

The oauth state was missing or invalid. Unknown location

My Startup.cs file looks like this:

     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
                    .AddControllersWithViews()
                    .AddRazorRuntimeCompilation();
                services.AddHttpContextAccessor();
                services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
                services.AddSingleton<IPaddleSettingsService, PaddleSettingsService>();
                services.AddScoped<IPaymentProviderService, PaddlePaymentProviderService>();
                services.Configure<AppConstants>(Configuration);

                services
                    .AddAuthentication(o =>
                    {
                        o.DefaultScheme = "Application";
                        o.DefaultSignInScheme = "External";
                    })
                    .AddCookie("Application")
                    .AddCookie("External")
                    .AddGoogle(o =>
                    {
                        o.ClientId = Configuration["GoogleClientId"];
                        o.ClientSecret = Configuration["GoogleClientSecret"];
                        o.CallbackPath = new PathString("/a/signin-callback");
                        o.ReturnUrlParameter = new PathString("/");
                    });
            }

            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                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.UseDefaultFiles();
                app.UseStaticFiles();
                app.UseRouting();
                app.UseAuthentication();
                app.UseAuthorization();
                app.UseHttpsRedirection();

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

The Controller:

    [Route("a")]
        /*[Route("Account")]*/ //Adding additional Account route to controller solves the problem. Why?
        public class AccountController : Controller
        {
            private readonly IOptions<AppConstants> _appConstants;
            private readonly IPaymentProviderService _paymentProvider;

            public AccountController(IOptions<AppConstants> appConstants, IPaymentProviderService paymentProvider)
            {
                _appConstants = appConstants;
                _paymentProvider = paymentProvider;
            }


            [Route("signin-google")]
            public IActionResult Signin(string returnUrl)
            {
                return new ChallengeResult(
                    GoogleDefaults.AuthenticationScheme,
                    new AuthenticationProperties
                    {
                        RedirectUri = Url.Action(nameof(GoogleCallback), new { returnUrl })
                    });
            }

            [Route("signin-callback")]
            public async Task<IActionResult> GoogleCallback(string returnUrl)
            {
                var authenticateResult = await HttpContext.AuthenticateAsync("External");

                if (!authenticateResult.Succeeded) return LocalRedirect("/#signinerr");

                var emailClaim = authenticateResult.Principal.FindFirst(ClaimTypes.Email);
                var activeSubscriptions = await _paymentProvider.GetUserActiveSubscriptions(emailClaim.Value);
                if (activeSubscriptions.Length != 0)
                {
                    var activeSubscription = activeSubscriptions.First(a => a.State == "active");
                    SetCookies(emailClaim.Value, activeSubscription.UserId, activeSubscription.SubscriptionId);
                    return LocalRedirect("/");
                }
                ClearCookies();
                return LocalRedirect("/#signinerr");
            }              
        }

The authorization url in google is below, it matches my local URL perfectly:

http://localhost:5000/a/signin-callback

When I select an account to authorize form google I get the error, but if I add

[Route("Account")]

the route to the controller then everything works fine. I can't understand why adding the Account route makes different? Any idea what is going on under the hood?

Verulamium answered 23/12, 2019 at 13:45 Comment(3)
Have you configured LoginPath to you custom Signin action? And does it can reach your custom Signin action?Pluperfect
@FeiHan Could you be more specified? What is LoginPath and where I should set it up?Verulamium
In Startup.cs, set .AddCookie("Application",options=> { options.LoginPath = "/signin-google"; })Pluperfect
D
4

I had the same problem and finally, I managed to fix it. The problem is that googleOptions.CallbackPath is not an API endpoint the will continue to execute after log in. It's an internal endpoint that serves for some internal auth logic. If you want to change your callback endpoint, you have to do it in another way.

More details are here in issue https://github.com/dotnet/aspnetcore/issues/22125

But to make a long story short - leave googleOptions.CallbackPath unchanged and pass return url as parameter using AuthenticationProperties

Deuteranope answered 22/5, 2020 at 8:15 Comment(3)
Registering the https://your-domain/signin-google in Google's API console sorted the problem for me. The googleoptions.CallbackPath property is left blank (as per the answer) AuthenticationProperties.RedirectUri = Url.Action("GoogleCallback") when redirecting to the Challenge. So there are two endpoints setup in Google's console - that did the trick. Thanks for your help!Arvell
WOW. I can't believe I wasted hours on this, LOL! cheers mate, you made ma day. The docs aren't clear about this, or I missed something. Yup, the signin-google path is used internally by the middleware.Saltant
If it is going to help anyone, I have documented some troubleshooting steps here. mahdikarimipour.com/blog/…Ossetic
A
0

To resolve issue with error message "The oauth state was missing or invalid. Unknown location", you just need make sure the callback URL of you code can accessed. In my app the aspnet core callback URL need "/" at the end of callback path like bellow:

options.CallbackPath = "/signin/callback/";
options.AccessDeniedPath = "/home";

And you must update in OAuth register App like basecamp or google, edit with the right path

Thank you, hopefully can fix your problem

Antonioantonius answered 3/8, 2023 at 2:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.