Anonymous probes against API routes return inconsistent status codes:
GET /api/invoices → 401
GET /api/invoices/1 → 302 → /Identity/Account/Login?ReturnUrl=…
GET /api/invoices/1/pdf → 302 → /Identity/Account/Login?ReturnUrl=…
POST /api/customers → 401
POST /api/invoices/1/mark-paid → 401
DELETE /api/invoices/1 → 302
Same authorization, different responses. JS clients that check if (res.status === 401) renewToken() get into redirect chains for some paths. Cookie-auth's challenge appears to sniff the Accept header / route shape and sometimes redirects.
Not a security bug
Both 401 and 302 block anonymous access. This is a UX wart, not a hole.
Fix
In the framework's cookie-auth setup, override OnRedirectToLogin to detect /api/* request paths and return 401 unconditionally:
services.ConfigureApplicationCookie(options =>
{
var existing = options.Events.OnRedirectToLogin;
options.Events.OnRedirectToLogin = ctx =>
{
if (ctx.Request.Path.StartsWithSegments("/api"))
{
ctx.Response.StatusCode = 401;
return Task.CompletedTask;
}
return existing(ctx);
};
});
Anonymous probes against API routes return inconsistent status codes:
Same authorization, different responses. JS clients that check
if (res.status === 401) renewToken()get into redirect chains for some paths. Cookie-auth's challenge appears to sniff the Accept header / route shape and sometimes redirects.Not a security bug
Both 401 and 302 block anonymous access. This is a UX wart, not a hole.
Fix
In the framework's cookie-auth setup, override
OnRedirectToLoginto detect/api/*request paths and return 401 unconditionally: