I am trying to setup a C# with React web application, using the C# backend as Backend-For-Frontend, so I can use cookie authentication. I am somewhat following this tutorial, but using the newest C#/React template.
I can get the authentication to work, but if I try to hit an endpoint with the [Authorize]
attribute, I get a 302 redirect to /Account/Login?ReturnUrl=(...)
. I would like it to be a 401, if there is no valid authentication cookie yet.
Here is a screenshot from the network tab in developer tools (Edge):
My authentication is registered in the Program.cs
class, like this:
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
o.Cookie.SameSite = SameSiteMode.Strict;
o.Cookie.HttpOnly = true;
})
.AddOpenIdConnect("Auth0", options => AuthenticationExtensions.ConfigureOpenIdConnect(options, configuration));
The AuthenticationExtensions.ConfigureOpenIdConnect()
looks like this. I have tried adding all the different events, I can imagine has anything to do with the redirect, but neither seems to have an effect:
internal static void ConfigureOpenIdConnect(OpenIdConnectOptions options, IConfiguration configuration)
{
options.Authority = $"https://{configuration["Auth0:Domain"]}";
options.ClientId = configuration["Auth0:ClientId"];
options.ClientSecret = configuration["Auth0:ClientSecret"];
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.ResponseMode = OpenIdConnectResponseMode.FormPost;
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("offline_access");
options.CallbackPath = new PathString("/callback");
options.ClaimsIssuer = "Auth0";
options.SaveTokens = true;
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProviderForSignOut = (context) =>
{
var logoutUri = $"https://{configuration["Auth0:Domain"]}/v2/logout?client_id={configuration["Auth0: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;
},
// I would expect one of these to work, but they don't.
OnRedirectToIdentityProvider = context => {
context.Response.StatusCode = 401;
context.HandleResponse();
return Task.CompletedTask;
},
OnAuthenticationFailed = context => {
context.Response.StatusCode = 401;
context.HandleResponse();
return Task.CompletedTask;
},
OnAccessDenied = context => {
context.Response.StatusCode = 401;
context.HandleResponse();
return Task.CompletedTask;
}
};
}
I run into this with Cookie Auth. I solved it by overriding these events.