Error from RemoteAuthentication: OpenIdConnectAuthenticationHandler: message.State is null or empty

Viewed 1605

Error from RemoteAuthentication: OpenIdConnectAuthenticationHandler: message.State is null or empty.. even after getting the code, id_token and token successfully.

I am using Razor pages along with .netcore and have registered the required middleware in startup.cs which you will found below.

ConfigureServices Function

        public void ConfigureServices(IServiceCollection services)
        {
            RegisterRazorPages(services);

            RegisterCoreServices(services);

            RegisterDataServices(services);

            RegisterVersioningServices(services);

            RegisterAntiforegery(services);
        }

        private void RegisterCoreServices(IServiceCollection services)
        {
            services.AddSingleton(Configuration);

            services.AddControllers(opts =>
            {
                opts.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());
                opts.RequireHttpsPermanent = true;
            })
                .AddNewtonsoftJson(opts =>
                {
                    opts.SerializerSettings.DateFormatString = "yyyyMMdd";
                    opts.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
                });


            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            // Add authentication services
            services.AddAuthentication(options => {
                //options.DefaultAuthenticateScheme = OpenIdConnectDefaults.AuthenticationScheme;
                //options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
            {
                options.Cookie.SameSite = SameSiteMode.None;
                options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
                options.Cookie.IsEssential = true;
            })
            .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => {
                //options.SignInScheme = "Cookies";
                // Set the authority to your Auth0 domain   
                options.Authority = $"https://{Configuration["OpenIdConnect:Domain"]}";
                options.RequireHttpsMetadata = true;
                options.MetadataAddress = $"https://{Configuration["OpenIdConnect:Domain"]}/.well-known/openid-configuration";
                options.UseTokenLifetime = true;
               
                // Configure the Auth0 Client ID and Client Secret
                options.ClientId = Configuration["OpenIdConnect:ClientId"];
                options.ClientSecret = Configuration["OpenIdConnect:ClientSecret"];
                // Set response type to code
                options.ResponseType = OpenIdConnectResponseType.CodeIdTokenToken;
                options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
                options.GetClaimsFromUserInfoEndpoint = true;
                options.UsePkce = true;
                // Configure the scope
                options.Scope.Clear();
                options.Scope.Add("openid");
                //options.Scope.Add("profile");
                options.Scope.Add("siam");

                options.SecurityTokenValidator = new JwtSecurityTokenHandler
                {
                    // Disable the built-in JWT claims mapping feature.
                    InboundClaimTypeMap = new Dictionary<string, string>()
                };

                options.TokenValidationParameters.NameClaimType = "name";
                options.TokenValidationParameters.RoleClaimType = "role";

                // Set the callback path, so Auth0 will call back to http://localhost:3000/callback
                // Also ensure that you have added the URL as an Allowed Callback URL in your Auth0 dashboard
                options.CallbackPath = new PathString("/Default");
                // Configure the Claims Issuer to be Auth0
                options.ClaimsIssuer = OpenIdConnectDefaults.AuthenticationScheme;

                options.SaveTokens = true;

                options.Events = new OpenIdConnectEvents
                {
                    OnRedirectToIdentityProvider = context =>
                    {
                        context.ProtocolMessage.SetParameter("audience", "http://localhost:3000/");

                        return Task.FromResult(0);
                    },
                    // handle the logout redirection 
                    OnRedirectToIdentityProviderForSignOut = (context) =>
                    {
                        var logoutUri = $"https://{Configuration["Siam:Domain"]}/v2/logout?client_id={Configuration["Siam:ClientId"]}";

                        var postLogoutUri = context.Properties.RedirectUri;
                        if (!string.IsNullOrEmpty(postLogoutUri))
                        {
                            if (postLogoutUri.StartsWith("/"))
                            {
                                // transform to absolute
                                var request = context.Request;
                                postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
                            }
                            logoutUri += $"&returnTo={ Uri.EscapeDataString(postLogoutUri)}";
                        }

                        context.Response.Redirect(logoutUri);
                        context.HandleResponse();

                        return Task.CompletedTask;
                    }
                };
            });

            services.AddAuthorization();
            services.AddHttpClient();

            services.AddHealthChecks()
                .AddCheck<AuthEndpointCheck>("auth_endpoint_check")
                .AddCheck<DbHealthCheck>("db_health_check");
        }

Configure function

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider apiVersionDescriptionProvider)
        {
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                RequireHeaderSymmetry = false,
                ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
            });
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseErrorHandlingMiddleware();
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            //app.UseCookiePolicy(new CookiePolicyOptions()
            //{
            //    HttpOnly = HttpOnlyPolicy.Always,
            //    Secure = CookieSecurePolicy.Always,
            //    MinimumSameSitePolicy = SameSiteMode.Strict
            //});
            app.UseRouting();

            

            // keep both between UseRouting() and UseEndpoints()
            app.UseAuthentication();
            app.UseAuthorization();


            app.UseHttpMetrics(options =>
            {
                options.RequestDuration.Histogram = Metrics.CreateHistogram("CCR_http_request_duration_seconds", string.Empty,
                    new HistogramConfiguration
                    {
                        Buckets = Histogram.LinearBuckets(
                            start: Convert.ToDouble(Configuration["Prometheus:Start"]),
                            width: Convert.ToDouble(Configuration["Prometheus:Width"]),
                            count: Convert.ToInt32(Configuration["Prometheus:Count"])),
                        LabelNames = new[] { "code", "method" }
                    });
            });

            app.UseMetricServer();
            app.UseSitHealthChecks();

            app.UseSwagger();
            app.UseSwaggerUI(opts =>
            {
                // build a swagger endpoint for each discovered API version
                foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
                {
                    opts.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
                }

                opts.RoutePrefix = string.Empty;
            });

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers().RequireAuthorization();
                endpoints.MapHealthChecks("/hc", new HealthCheckOptions() { }).RequireAuthorization();
                endpoints.MapMetrics().RequireAuthorization();
                endpoints.MapRazorPages();
            });

            IdentityModelEventSource.ShowPII = true;
        }

Problem Description In the startup.cs file, i have set callback url to the protected homepage. When the application is stated, it will challange the oauth and here is the challenge code of indexPage. After finishing this challenge, the page should redirect to Default Page which is the home page of Application and is protected.

public async Task OnGetAsync()
        {
            if (User.Identity.IsAuthenticated)
            {
                string accessToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);

                // if you need to check the Access Token expiration time, use this value
                // provided on the authorization response and stored.
                // do not attempt to inspect/decode the access token
                DateTime accessTokenExpiresAt = DateTime.Parse(
                    await HttpContext.GetTokenAsync("expires_at"),
                    CultureInfo.InvariantCulture,
                    DateTimeStyles.RoundtripKind);

                string idToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.IdToken);
            }
            else
            {
                string accessToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
                string returnUrl = "/Default";
                await HttpContext.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties() { RedirectUri = returnUrl });
                //Challenge(OpenIdConnectDefaults.AuthenticationScheme);
            }
        }

and in the response following output has been generated from the brower.

enter image description here

In 4th call i am getting the id_token, token and code in response and after that app is redirecting to the mentioned /Default route in 5th call, where again some redirect occus in 6th call which i dont understand.

In the 6th call i am loosing all the parameter, and i dont have any cookies anymore. The logs are then showing the following exception.

2020-08-17 14:38:11.337 +02:00 [INF] Error from RemoteAuthentication: OpenIdConnectAuthenticationHandler: message.State is null or empty..
2020-08-17 14:38:11.381 +02:00 [ERR] An error was encountered while handling the remote login.
System.Exception: An error was encountered while handling the remote login.
 ---> System.Exception: OpenIdConnectAuthenticationHandler: message.State is null or empty.
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at SIT.WebApi.Infrastructure.Middleware.ErrorHandlingMiddleware.Invoke(HttpContext context)
2020-08-17 14:38:11.397 +02:00 [INF] Request finished in 62.128ms 500 application/json

Question

  1. Why i need give callback url, while my server is automatically
    redirecting and authenticating the users upon hitting the
    authorization endpoint. Server is using kerberos windows
    authentication.
  2. What is the different between callback url in startup.cs, and the redirect url in index page.
  3. If i am not mentioning the callback url, my app is by default redirecting toward /signin-oidc route, why?
  4. How should i overcome this error?
  5. How can i store the user information into HttpContext.User after getting the tokens, code and id_token etc.
0 Answers
Related