Home > Software engineering >  The oauth state was missing or invalid - Unknown location
The oauth state was missing or invalid - Unknown location

Time:01-31

I am using both Google and Facebook authentication mechanisms in my .NET 7.0 app and they both work fine locally. When deployed in my DEV environment I am getting exceptions when coming back from Google/Facebook. So the challenge works correctly, I am able to authenticate at their side but the callback fails, saying:

Exception: The oauth state was missing or invalid.
Unknown location

I am being redirected to https://my.website.com/signin-google with the state in a querystring parameter. This is the expected behavior as I did not configure an explicit callback path and by default it's set to signin-google and signin-facebook. But somehow it seems like the RemoteAuthenticationHandler does not think this matches the callback path so it's not handling the request? Or would the issue be in the OAuthHandler.HandleRemoteAuthenticateAsync? Maybe when unprotecting the state data? But then why would this work locally?

My setup:

services.AddAuthentication()
    .AddGoogle("google", options =>
    {
        options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
        options.ClientId = AppSettings.Instance.GoogleClientId;
        options.ClientSecret = AppSettings.Instance.GoogleClientSecret;
    })
    .AddFacebook("facebook", options =>
    {
        options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
        options.AppId = AppSettings.Instance.FacebookAppId;
        options.AppSecret = AppSettings.Instance.FacebookAppSecret;
    });

Edit: Could this possibly be linked to the fact I am using 2 servers in my DEV environment and that it uses something machine-related to unprotect the state so it does not work when I land on the other machine?

CodePudding user response:

It turns out this was due to the fact I am now deploying the application on multiple distributed servers, accessed via a load balancer. This article here helped me to understand how data protection works in ASP.NET Core.

By default key-rotation system is used and the keys are generated by the machine and persisted to %LOCALAPPDATA%\ASP.NET\DataProtection-Keys. So of course this does not work anymore when you scale up your applications.

So instead I decided to store the data protection keys in a shared database so all machines will use the same key:

  1. Add reference to Nuget Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.

  2. Create a DbContext that inherits from IDataProtectionKeyContext

  3. Register your DbContext

  4. Setup your data protection to use the DbContext as:

    builder.Services.AddDataProtection()
        .PersistKeysToDbContext<DataProtectionKeyContext>();
    
  • Related