OAuth: The oauth state was invalid or missing

See original GitHub issue

Describe the bug

I’m trying to set up OAuth with AdobeIO. I haven’t found any .NET libs around for it so I am trying to roll it myself.

It redirects me to Adobe just fine, but there’s something wrong with the callback because it always tells me the oauth state is invalid or missing.

Upon further investigation using a quick ISecureDataFormat I saw that the callback initially does have the oauth state which gets unprotected successfully, but Unprotect gets called again immediately afterwards with no protected text.

To Reproduce

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services
                .AddAuthentication()
                .AddOAuth("adobe", options =>
                {
                    var handler = new HttpClientHandler();
                    handler.ServerCertificateCustomValidationCallback = (HttpRequestMessage req, X509Certificate2 cert, X509Chain chain, SslPolicyErrors errors) => {
                        Console.WriteLine("HELLO");
                        return true;
                    };
                    var httpClient = new HttpClient(handler);
                    options.ClientId = Configuration["AdobeAuth:ClientId"];
                    options.ClientSecret = Configuration["AdobeAuth:ClientSecret"];
                    options.CallbackPath = new Microsoft.AspNetCore.Http.PathString(Configuration["AdobeAuth:CallbackPath"]);
                    options.AuthorizationEndpoint = Configuration["AdobeAuth:AuthorizationEndpoint"];
                    options.TokenEndpoint = Configuration["AdobeAuth:AuthorizationEndpoint"];
                    options.Backchannel = httpClient;
                    options.SaveTokens = false;
                    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;

                    options.Scope.Clear();

                    var scopes = Configuration["AdobeAuth:Scopes"].Split(',');
                    foreach(var scope in scopes)
                    {
                        options.Scope.Add(scope);
                    }
                    options.Events.OnAccessDenied += (context) => {
                        Console.WriteLine("access denied");
                        return Task.CompletedTask;
                    };
                    options.Events.OnTicketReceived += (context) => {
                        Console.WriteLine("ticket received");
                        return Task.CompletedTask;
                    };
                    options.Events.OnCreatingTicket += (context) => {
                        Console.WriteLine("creating ticket");
                        return Task.CompletedTask;
                    };
                    options.Events.OnRedirectToAuthorizationEndpoint += (RedirectContext<OAuthOptions> context) => {
                        Console.WriteLine("redirecting to auth endpoint");
                        return Task.CompletedTask;
                    };
                    options.Events.OnRemoteFailure += (context) => {
                        Console.WriteLine("remote failure");
                        return Task.CompletedTask;
                    };
                    options.StateDataFormat = new TestSecureDataFormat();
                });
        }

        // 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();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

        public class TestSecureDataFormat : ISecureDataFormat<AuthenticationProperties>
        {
            private readonly IDataProtector protector;
            public TestSecureDataFormat()
            {
                protector = DataProtectionProvider.Create("server").CreateProtector("authentication");
            }
            public string Protect(AuthenticationProperties data)
            {
                var json = Newtonsoft.Json.JsonConvert.SerializeObject(data);
                var p = protector.Protect(json);
                return p;
            }

            public string Protect(AuthenticationProperties data, string purpose)
            {
                return Protect(data);
            }

            [return: MaybeNull]
            public AuthenticationProperties Unprotect(string protectedText)
            {
                var u = protector.Unprotect(protectedText);
                var props = Newtonsoft.Json.JsonConvert.DeserializeObject<AuthenticationProperties>(u);
                return props;
            }

            [return: MaybeNull]
            public AuthenticationProperties Unprotect(string protectedText, string purpose)
            {
                return Unprotect(protectedText);
            }
        }
[Route("{controller}")]
    public class AuthController : Controller
    {
        private readonly IConfiguration configuration;
        public AuthController(IConfiguration configuration)
        {
            this.configuration = configuration;
        }

        [HttpGet("login")]
        public IActionResult Login()
        {
            var properties = new OAuthChallengeProperties()
            {
                RedirectUri = new PathString(this.configuration["AdobeAuth:CallbackPath"]),
            };

            return Challenge(properties, "adobe");
        }
    }
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <UserSecretsId>32de766e-0589-4a13-8b88-f04d4faa8c58</UserSecretsId>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
  </ItemGroup>
</Project>

Please ignore the Console.WriteLines, I have been pulling my hair out trying to figure this out for a while 😪

I also have no idea why I need to override the server cert verification. Either my machine doesn’t trust adobe’s cert, or they don’t trust mine? I’m not sure.

Further technical details

  • ASP.NET Core version: 5
  • Include the output of dotnet --info:
dotnet --info
.NET SDK (reflecting any global.json):
 Version:   5.0.202     
 Commit:    db7cc87d51  

Runtime Environment:    
 OS Name:     Windows   
 OS Version:  10.0.19042
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\5.0.202\

Host (useful for support):
  Version: 5.0.5
  Commit:  2f740adc14

.NET SDKs installed:
  2.1.523 [C:\Program Files\dotnet\sdk]
  3.1.201 [C:\Program Files\dotnet\sdk]
  3.1.408 [C:\Program Files\dotnet\sdk]
  5.0.103 [C:\Program Files\dotnet\sdk]
  5.0.202 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.All 2.1.25 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.27 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.25 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.27 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.14 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.1.25 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.27 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.8 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  • The IDE (VS / VS Code/ VS4Mac) you’re running on, and its version
Version: 1.55.2 (system setup)
Commit: 3c4e3df9e89829dce27b7b5c24508306b151f30d
Date: 2021-04-13T09:35:57.887Z
Electron: 11.3.0
Chrome: 87.0.4280.141
Node.js: 12.18.3
V8: 8.7.220.31-electron.0
OS: Windows_NT x64 10.0.19042

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:18 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
biltongzacommented, Apr 30, 2021

Turns out the redirect was happening because the TokenEndpoint is https://ims-na1.adobelogin.com/ims/token not https://ims-na1.adobelogin.com/ims/authorize/v2 🙃

1reaction
Tratchercommented, Apr 29, 2021

I was able to run this locally and found the issue. The app receives the callback: GET https://localhost:5001/signin-adobe?code=...&state=… It sends a request on the backchannel HttpClient to redeme the code for a token. This fails and returns a 302 redirect to Location: https://localhost:5001/signin-adobe?error=invalid_scope. The HttpClient automatically follows the redirect, making a new request back to your own server and signin path, but without the state.

I’m not sure why they thought a redirect was an appropriate way to report errors from the token endpoint. It does explain why you needed to add ServerCertificateCustomValidationCallback in startup, HttpClient didn’t trust your local development certificate for the redirected request (that part works for me, I trusted the dev cert).

I was able to supress the redirect like this:

                    var handler = new HttpClientHandler();
                    handler.AllowAutoRedirect = false;

To see the real error message:

System.Exception: An error was encountered while handling the remote login.
 ---> System.Exception: OAuth token endpoint failure: Status: Redirect;Headers: Date: Thu, 29 Apr 2021 18:25:08 GMT
Connection: keep-alive
Cache-Control: no-store
Set-Cookie: relay=aaff2386-255d-4686-bb31-9b6167a1130b; Path=/; Secure; SameSite=None, ftrset=682; Path=/; Secure; HttpOnly; SameSite=None, ftrset=682; Path=/; Secure; HttpOnly; SameSite=None
P3P: CP="IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA"
Server: ASIT
Location: https://localhost:5001/signin-adobe?error=invalid_scope
Vary: Accept-Encoding
X-DEBUG-ID: aaff2386-255d-4686-bb31-9b6167a1130b
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Via: e-uw2,e-ue1
;Body: ;
   --- 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)

I’ll let you sort out what’s wrong with the scope.

Read more comments on GitHub >

github_iconTop Results From Across the Web

The oauth state was missing or invalid. An error was ...
I am facing issues while implementing external login in asp.net core 2.2 (mvc) without using identity. After signing in to google it redirect ......
Read more >
The oauth state was missing or invalid. Unknown location
I created simple ASP.NET Core 3 Web API application. I added new external login oauth provider (let it be Google) and nothing else....
Read more >
The oauth state was missing or invalid. (ASP.NET Core ...
Coding example for the question Exception: The oauth state was missing or invalid. (ASP.NET Core external identifier OAuth)-.net-core.
Read more >
The oauth state was missing or invalid : r/dotnet
I'm trying to integrate google authentication in my Blazor Server App. But evertime i try to signin with google, i get this error...
Read more >
Invalid OAuth State
I've completed all the steps, and when I authorise and save the page, it gives me the error “Invalid OAuth State”. I still...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found