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.
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
- 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. - What is the different between callback url in startup.cs, and the redirect url in index page.
- If i am not mentioning the callback url, my app is by default redirecting toward /signin-oidc route, why?
- How should i overcome this error?
- How can i store the user information into HttpContext.User after getting the tokens, code and id_token etc.
