I wrote a CustomCookieAuthenticationHandler because I don't like the way CookieAuthenticationHandler.HandleForbiddenAsync() manages results, in particular the fact that it redirects the user to another URL as I think the response should be returned to the URL that was requested.
I basically replaced the code with a status code setter to return 404 which is then handled by the error handler. I would like to know if this implementation is safe.
CustomCookieAuthenticationHandler
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.Options;
using System.Net;
using System.Text.Encodings.Web;
namespace Frontend.Authorization.Handlers
{
    public class CustomCookieAuthenticationHandler(IOptionsMonitor<CookieAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder) : CookieAuthenticationHandler(options, logger, encoder)
    {
        /// Returns 404 instead of redirecting to the AccessDeniedPath
        protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
        {
            await Task.FromResult(Context.Response.StatusCode = (int)HttpStatusCode.NotFound);
        }
    }
}
CustomCookieExtensions (Copied from CookieExtensions, I just changed the authentication handler type)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Frontend.Authorization.Handlers;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection;
/// <summary>
/// Extension methods to configure custom cookie authentication. Custom cookie authentication uses the default cookie authentication with some tweaks to the authentication handler used
/// </summary>
public static class CustomCookieExtensions
{
    public static AuthenticationBuilder AddCustomCookie(this AuthenticationBuilder builder)
        => builder.AddCustomCookie(CookieAuthenticationDefaults.AuthenticationScheme);
    public static AuthenticationBuilder AddCustomCookie(this AuthenticationBuilder builder, string authenticationScheme)
        => builder.AddCustomCookie(authenticationScheme, configureOptions: null!);
    public static AuthenticationBuilder AddCustomCookie(this AuthenticationBuilder builder, Action<CookieAuthenticationOptions> configureOptions)
        => builder.AddCustomCookie(CookieAuthenticationDefaults.AuthenticationScheme, configureOptions);
    public static AuthenticationBuilder AddCustomCookie(this AuthenticationBuilder builder, string authenticationScheme, Action<CookieAuthenticationOptions> configureOptions)
        => builder.AddCustomCookie(authenticationScheme, displayName: null, configureOptions: configureOptions);
    public static AuthenticationBuilder AddCustomCookie(this AuthenticationBuilder builder, string authenticationScheme, string? displayName, Action<CookieAuthenticationOptions> configureOptions)
    {
        builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<CookieAuthenticationOptions>, PostConfigureCookieAuthenticationOptions>());
        builder.Services.AddOptions<CookieAuthenticationOptions>(authenticationScheme).Validate(o => o.Cookie.Expiration == null, "Cookie.Expiration is ignored, use ExpireTimeSpan instead.");
        return builder.AddScheme<CookieAuthenticationOptions, CustomCookieAuthenticationHandler>(authenticationScheme, displayName, configureOptions);
    }
}
HomeController
    public class HomeController : Controller
    {
        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View();
        }
    }
Program.cs
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
    .AddCustomCookie(options =>
    {
        options.Cookie = new()
        {
            Name = "auth",
            SameSite = SameSiteMode.Lax,
            Path = "/",
            HttpOnly = true,
            IsEssential = true,
            MaxAge = TimeSpan.FromDays(6 * 30)
        };
        options.ExpireTimeSpan = TimeSpan.FromDays(6 * 30);
    });
app.UseStatusCodePagesWithReExecute("/Home/Error");
protected override Task HandleForbiddenAsync(AuthenticationProperties properties)could be implemented like this:{ Context.Response.StatusCode = (int)HttpStatusCode.NotFound; return Task.CompletedTask; }\$\endgroup\$RedirectUri, then it will redirected to the same page!. if that is not enough, then maybe overridingCookieAuthenticationEvents.RedirectToAccessDeniedwould give more control on it. \$\endgroup\$