Hi all,

I'm learning Blazor (.NET 9 on VS2022). I'm trying to develop a simple login page, but I keep getting the error: "A valid antiforgery token was not provided with the request. Add an antiforgery token, or disable antiforgery validation for this endpoint.".

Can anybody please help me?

program.cs

Code:
using M2M;
using M2M.Components;
using M2M.Components.Account;
using M2M.Data;
using M2M.Models.User;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Syncfusion.Blazor;

var builder = WebApplication.CreateBuilder(args);

string pgSQLServer = builder.Configuration.GetSection("PG_SQL").GetSection("Server").Value;
string pgSQLDBName = builder.Configuration.GetSection("PG_SQL").GetSection("DB_Name").Value;
string pgSQLDBUser = builder.Configuration.GetSection("PG_SQL").GetSection("DB_User").Value;
string pgSQLDBPassword = builder.Configuration.GetSection("PG_SQL").GetSection("DB_User_Password").Value;
int pgPoolSize = Convert.ToInt32(builder.Configuration.GetSection("PG_SQL").GetSection("DB_Pool_Size").Value);

string pgSQLConnectionString = "Server=" + M2M.Models.AppSettings.PG_SQL.Server + ";Database=" + M2M.Models.AppSettings.PG_SQL.DB_Name + ";Port=5432;User ID=" + M2M.Models.AppSettings.PG_SQL.DB_User + ";Password=" + M2M.Models.AppSettings.PG_SQL.DB_User_Password + ";Keepalive=300; Pooling = true; Minimum Pool Size = 0; Maximum Pool Size = " + pgPoolSize + "; Connection Idle Lifetime=300; CommandTimeout=300; Tcp Keepalive=true; Include Error Detail=true";

M2M.Models.AppSettings.PG_SQL.Connection_String = pgSQLConnectionString;

// Add services to the container.

builder.Services.AddRazorComponents().AddInteractiveServerComponents();
builder.Services.AddSignalR(o => { o.MaximumReceiveMessageSize = 102400000; });
builder.Services.AddSyncfusionBlazor();
//builder.Services.AddSingleton<PdfService>();
//builder.Services.AddSingleton<ExcelService>();
builder.Services.AddMemoryCache();
builder.Services.AddCascadingAuthenticationState();

builder.Services.AddScoped<IUserManager, UserManager>();
builder.Services.AddScoped<IUserRepository, UserRepository>();

builder.Services.AddDbContext<CookieReadersContext>(options =>
{
    options.UseNpgsql(pgSQLConnectionString);
});

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
    options.Cookie.Name = ".AspNetCore.Cookies";
    options.LoginPath = "/";
    options.ReturnUrlParameter = "ReturnUrl";
    options.AccessDeniedPath = "/Access_Denied";
    options.LogoutPath = "/Logout";
    options.SlidingExpiration = true;
    options.ExpireTimeSpan = TimeSpan.FromHours(M2M.Models.AppSettings.SESSION_TIMEOUT);
    options.Cookie.MaxAge = options.ExpireTimeSpan;
});

builder.Services.AddTransient<CustomCookieAuthenticationEvents>();
builder.Services.AddHttpContextAccessor();
builder.Services.AddMemoryCache();

builder.Services.AddAntiforgery(opts => opts.Cookie.Name = "__RequestVerificationToken");

builder.Services.Configure<CookiePolicyOptions>(options =>
{
    // This lambda determines whether user consent for non-essential cookies is needed for a given request.  
    options.Secure = CookieSecurePolicy.Always;
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy = SameSiteMode.None;
});

builder.Services.AddScoped<AppStateService>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseCookiePolicy();

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();

app.MapStaticAssets();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

// Add additional endpoints required by the Identity /Account Razor components.
app.MapAdditionalIdentityEndpoints();

app.Run();
login.razor

Code:
@page "/"

@using System.ComponentModel.DataAnnotations
@using M2M.Models.User
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@using M2M.Data

@inject AppStateService appStateService
@inject NavigationManager NavManager
@inject IJSRuntime JSRuntime

@inject IUserRepository UserRepositoty
@inject ILogger<Login> Logger
@inject NavigationManager NavigationManager

@attribute [AllowAnonymous]

<PageTitle>Log in</PageTitle>

<h1>Log in</h1>
<div class="row">
    <div class="col-lg-6">
        <section>
            <StatusMessage Message="@errorMessage" />
            <EditForm Model="Input" method="post" OnValidSubmit="LoginUser" FormName="login">
                <DataAnnotationsValidator />
                <AntiforgeryToken />
                <h2>Use a local account to log in.</h2>
                <hr />
                <div class="form-floating mb-3">
                    <InputText @bind-Value="Input.Email" id="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" />
                    <label for="Input.Email" class="form-label">Email</label>
                    <ValidationMessage For="() => Input.Email" class="text-danger" />
                </div>
                <div class="form-floating mb-3">
                    <InputText type="password" @bind-Value="Input.Password" id="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="password" />
                    <label for="Input.Password" class="form-label">Password</label>
                    <ValidationMessage For="() => Input.Password" class="text-danger" />
                </div>
                <div class="checkbox mb-3">
                    <label class="form-label">
                        <InputCheckbox @bind-Value="Input.RememberMe" class="darker-border-checkbox form-check-input" />
                        Remember me
                    </label>
                </div>
                <div>
                    <button type="submit" class="w-100 btn btn-lg btn-primary">Log in</button>
                </div>
                <div>
                    <p>
                        <a href="Account/ForgotPassword">Forgot your password?</a>
                    </p>
                    <p>
                        <a href="@(NavigationManager.GetUriWithQueryParameters("Account/Register", new Dictionary<string, object?> { ["ReturnUrl"] = ReturnUrl }))">Register as a new user</a>
                    </p>
                    <p>
                        <a href="Account/ResendEmailConfirmation">Resend email confirmation</a>
                    </p>
                </div>

            </EditForm>
        </section>
    </div>
    @* <div class="col-lg-4 col-lg-offset-2">
        <section>
            <h3>Use another service to log in.</h3>
            <hr />
            <ExternalLoginPicker />
        </section>
    </div> *@
</div>

@code {
    private string? errorMessage;

    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;
    private UserManager UserManager { get; set; } = new UserManager();
  
    [SupplyParameterFromForm]
    private Models.User.Login Input { get; set; } = new();

    [SupplyParameterFromQuery]
    private string? ReturnUrl { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (HttpMethods.IsGet(HttpContext.Request.Method))
        {
            // Clear the existing external cookie to ensure a clean login process
            await UserManager.SignOut(this.HttpContext);
        }
    }

    public async Task LoginUser()
    {
        
        var result = await UserManager.SignIn(this.HttpContext, Input);
        
       if (result.usersPid > 0)
      {
           Logger.LogInformation("User logged in.");
           RedirectManager.RedirectTo(ReturnUrl);
      }
       else
      {
        // blah blah blah
       }
    }
    
}