New to Blazor - A valid antiforgery token was not provided with the request.

Dondon510 221 Reputation points
2025-01-25T18:30:51.9566667+00:00

Hi all,

Can any body please give me an advice so I can move forward to the main page, why I'm getting "A valid antiforgery token was not provided with the request. Add an antiforgery token, or disable antiforgery validation for this endpoint." on login.razor of my 1st Blazor Project (learning process)

program.cs

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 = "/User/Login";
    options.ReturnUrlParameter = "ReturnUrl";
    options.AccessDeniedPath = "/User/Login";
    options.LogoutPath = "/User/Logout";
    options.SlidingExpiration = true;
    options.ExpireTimeSpan = TimeSpan.FromHours(M2M.Models.AppSettings.SESSION_TIMEOUT);
    options.Cookie.MaxAge = options.ExpireTimeSpan;
});

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

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

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

@page "/"

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

@inject ILogger<Login> Logger
@inject NavigationManager NavigationManager

<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 />

                <h2>Use a local account to log in.</h2>
                <hr />
                @* <ValidationSummary class="text-danger" role="alert" /> *@
                <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>

                <AntiforgeryToken />

            </EditForm>
        </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);
            // await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
        }
    }

    public async Task LoginUser()
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, set lockoutOnFailure: true

        await UserManager.SignIn(this.HttpContext, Input);
    }
    
}

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,769 questions
Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,657 questions
0 comments No comments
{count} votes

4 answers

Sort by: Most helpful
  1. AgaveJoe 29,761 Reputation points
    2025-01-25T20:06:12.26+00:00

    You did not tell us what kind or version of Blazor application you are building.

    Anti-forgery support is baked in with Blazor. It is not clear why you are modifying the antiforgery cookie name by adding an underscore to "___RequestVerificationToken". I'm guessing the input is still named "__RequestVerificationToken" (two underscores). Use the browser's dev tools to verify the anti-forgery input matches what you named the cookie.

    https://learn.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-9.0&tabs=visual-studio

    I recommend creating a new Blazor project to study how the anti-forgery feature works. If you want to modify the out-of-the-box experience then you can make changes without worrying if the changes affect other custom services you've created.

    More importantly though, the general design is not going to work. Blazor runs in the browser so there's no HttpContext when navigating to a new page. Plus it is not recommended to relay on HttpContext in a Blazor application as explained in the linked documentation.

    await UserManager.SignIn(this.HttpContext, Input);  
    

    This is another situation where you should take some time to understand Blazor fundamentals. I recommend creating a new Blazor project and add the "Individual Account" option. The template code will reveal how to work an authentication cookie in a Blazor application. Also see the link above which explains how authentication works in Blazor.

    0 comments No comments

  2. Bruce (SqlWork.com) 70,611 Reputation points
    2025-01-26T03:03:01.84+00:00

    your code is confusing.

    the supporting identity code for Blazor is usually done with razor pages, that perform postbacks. the UserManger uses razor pages. when you code calls SignIn() it tries to process the post data of the httpcontext, but there is none.

    also there is only one httpcontext for the life of a Blazor application. it is valid only for the static pre-render of the blazor app. for interactive components its null. you should have defined as:

        [CascadingParameter]
        private HttpContext? HttpContext { get; set; }; // not null == prerender
    

    any values of the httpcontext you wanted in interactive components should have been injected or if related to authorization, added to the authorization state provider.

    0 comments No comments

  3. Dondon510 221 Reputation points
    2025-01-26T12:18:22.1033333+00:00

    Hi all,

    thank you so much your kindly replies, I'm in learning process of Blazor, and I use NET Core 9 (VS 2022).

    Ok, I have created a new Blazor project (web app) + PosgreSQL-14

    program.cs

    using M2M.Components;
    using M2M.Components.Account;
    using M2M.Data;
    using Microsoft.AspNetCore.Components.Authorization;
    using Microsoft.AspNetCore.Identity;
    using Microsoft.EntityFrameworkCore;
    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.AddCascadingAuthenticationState();
    builder.Services.AddScoped<IdentityUserAccessor>();
    builder.Services.AddScoped<IdentityRedirectManager>();
    builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>();
    builder.Services.AddAuthentication(options =>
        {
            options.DefaultScheme = IdentityConstants.ApplicationScheme;
            options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
        })
        .AddIdentityCookies();
    builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseNpgsql(pgSQLConnectionString));
    builder.Services.AddDatabaseDeveloperPageExceptionFilter();
    builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddSignInManager()
        .AddDefaultTokenProviders();
    builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();
    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.UseHttpsRedirection();
    app.UseAntiforgery();
    app.MapStaticAssets();
    app.MapRazorComponents<App>()
        .AddInteractiveServerRenderMode();
    // Add additional endpoints required by the Identity /Account Razor components.
    app.MapAdditionalIdentityEndpoints();
    app.Run();
    type here
    

    login.razor

     @page "/"
    
    @using System.ComponentModel.DataAnnotations
    @using Microsoft.AspNetCore.Authentication
    @using Microsoft.AspNetCore.Identity
    @using M2M.Data
    
    @inject SignInManager<ApplicationUser> SignInManager
    @inject ILogger<Login> Logger
    @inject NavigationManager NavigationManager
    @inject IdentityRedirectManager RedirectManager
    
    <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 />
                    <h2>Use a local account to log in.</h2>
                    <hr />
                    <ValidationSummary class="text-danger" role="alert" />
                    <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!;
    
        [SupplyParameterFromForm]
        private InputModel 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 HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
            }
        }
    
        public async Task LoginUser()
        {
            // This doesn't count login failures towards account lockout
            // To enable password failures to trigger account lockout, set lockoutOnFailure: true
            var result = await SignInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
            if (result.Succeeded)
            {
                Logger.LogInformation("User logged in.");
                RedirectManager.RedirectTo(ReturnUrl);
            }
            else if (result.RequiresTwoFactor)
            {
                RedirectManager.RedirectTo(
                    "Account/LoginWith2fa",
                    new() { ["returnUrl"] = ReturnUrl, ["rememberMe"] = Input.RememberMe });
            }
            else if (result.IsLockedOut)
            {
                Logger.LogWarning("User account locked out.");
                RedirectManager.RedirectTo("Account/Lockout");
            }
            else
            {
                errorMessage = "Error: Invalid login attempt.";
            }
        }
    
        private sealed class InputModel
        {
            [Required]
            [EmailAddress]
            public string Email { get; set; } = "";
    
            [Required]
            [DataType(DataType.Password)]
            public string Password { get; set; } = "";
    
            [Display(Name = "Remember me?")]
            public bool RememberMe { get; set; }
        }
    }
    
    

    with the above codes (I don't know what to do), I just run it, but I got the following exception

    System.ArgumentException: 'Host can't be null'

    enter image description here

    last but not least, I have my own User_Login.cs, and I want when the user clicks Login button, then it will executes the below, how to do this?

    User_Login.cs

    try
    {
        using (NpgsqlConnection conn = new NpgsqlConnection(Models.AppSettings.PG_SQL.Connection_String))
        {
            try
            {
                string xUserEmail = DES.TripleDesEncrypt(userEmail.Trim().ToLower());
                string xUserPassword = DES.TripleDesEncrypt(userPassword.Trim());
    
                string sql = "select u.pid usersPid, u.user_name userName, u.user_password, u.user_email userEmail, u.user_mobile userMobile, u.user_role userRole, u.super super, u.last_login " +
                        "From users u " +
                
                        "u.user_password=@User_Password And " +
                        "u.active=true";
    
                using (var dr = conn.ExecuteReader(sql, new
                {
                    User_Email = xUserEmail,
                    User_Password = xUserPassword
                }))
                {
                    if (dr.Read())
                    {
                        // do some process here
                    }
                }
            }
            catch (Exception e)
            {
                           // blah blah
            }
            finally { }
        }
    

  4. Ruikai Feng - MSFT 2,751 Reputation points Microsoft Vendor
    2025-01-27T07:41:18.14+00:00

    Hi,@Dondon510

    For the error "A valid antiforgery token was not provided with the request. Add an antiforgery token, or disable antiforgery validation for this endpoint." just remove <AntiforgeryToken /> inside your EditForm. Forms based on EditForm automatically enable antiforgery support.See document here

    For the second error "Host can't be null" it indicates there's something get wrong with your database connection string,it lacks the Host parameter

    Host=127.0.0.1; Port=xxxx; Database=xxxx;User ID=xxxx;Password=******
    
    
    

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,

    Ruikai Feng

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.