Persilsoft.Turnstile.Blazor 1.0.1

dotnet add package Persilsoft.Turnstile.Blazor --version 1.0.1
                    
NuGet\Install-Package Persilsoft.Turnstile.Blazor -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Persilsoft.Turnstile.Blazor" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Persilsoft.Turnstile.Blazor" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Persilsoft.Turnstile.Blazor" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Persilsoft.Turnstile.Blazor --version 1.0.1
                    
#r "nuget: Persilsoft.Turnstile.Blazor, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Persilsoft.Turnstile.Blazor@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Persilsoft.Turnstile.Blazor&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Persilsoft.Turnstile.Blazor&version=1.0.1
                    
Install as a Cake Tool

Persilsoft.Turnstile.Blazor

Persilsoft.Turnstile.Blazor is a Blazor component that integrates Cloudflare Turnstile CAPTCHA into Blazor WebAssembly and Blazor Server applications.

It provides:

  • ✅ A reusable CAPTCHA component.
  • ✅ A service to manage Turnstile lifecycle.
  • ✅ Full JavaScript interop handling.
  • ✅ The ability to retrieve CAPTCHA tokens and send them to your backend for secure verification.

🚀 Installation

  1. Install the NuGet package:
dotnet add package Persilsoft.Turnstile.Blazor
  1. Register the Turnstile services in your Blazor application's DI container:
using Persilsoft.Turnstile.Shared.Options;
using Persilsoft.Turnstile.Blazor;

Action<TurnstileOptions> turnstileOptionsConfigurator = options =>
    builder.Configuration.GetRequiredSection(TurnstileOptions.SectionKey).Bind(options);

builder.Services.AddTurnstileServices(turnstileOptionsConfigurator);

🔧 Configuration

Add the following section to your appsettings.json:

"TurnstileOptions": {
  "WebApiBaseAddress": "https://localhost:7292",
  "SiteKey": "YOUR_SITE_KEY"
}
Key Description
WebApiBaseAddress The base URL of your backend where the token verification endpoint resides.
SiteKey Your public site key from Cloudflare Turnstile.

🔐 Backend Verification Requirement

⚠️ Important:
The CAPTCHA component generates a validation token. Your backend must verify this token with Cloudflare's /siteverify API to ensure it is valid.

Option 1 — Manual verification (DIY):

[HttpPost("api/turnstile-verify")]
public async Task<IActionResult> Verify([FromBody] CaptchaVerificationRequest request)
{
    var secret = _config["Turnstile:SecretKey"];
    var httpClient = _httpClientFactory.CreateClient();

    var parameters = new Dictionary<string, string>
    {
        { "secret", secret },
        { "response", request.Token }
    };

    var content = new FormUrlEncodedContent(parameters);
    var response = await httpClient.PostAsync("https://challenges.cloudflare.com/turnstile/v0/siteverify", content);
    var json = await response.Content.ReadAsStringAsync();

    var result = JsonSerializer.Deserialize<TurnstileResponse>(json);

    if (result != null && result.Success)
        return Ok(new { success = true });

    return BadRequest(new { success = false, errors = result?.ErrorCodes });
}

Option 2 — Use Persilsoft.Turnstile.Server

💡 Recommended: You can avoid implementing the verification endpoint manually by using the complementary NuGet package Persilsoft.Turnstile.Server.

With it, you simply register the backend service and call TurnstileService.VerifyAsync(token) — no need to deal with HttpClient, FormUrlEncodedContent, or JSON parsing.


🧠 Component Parameters

Parameter Type Required Description
Action string Action name for token verification context.
Theme TurnstileTheme? Widget theme: Auto, Dark, or Light.
Language string? Language code (e.g., en, es-PE).
Size TurnstileSize Widget size: Normal, Compact, Invisible.
Appearance TurnstileAppearance Appearance behavior: Always or Execute.
OnSuccess EventCallback<string> Triggered with the CAPTCHA token when successfully completed.
OnError EventCallback Triggered when CAPTCHA encounters an error.
OnExpired EventCallback Triggered when the CAPTCHA token expires.

💡 Example Usage

Razor Page Example

@page "/turnstile"
<PageTitle>Turnstile</PageTitle>

<h3>Turnstile CAPTCHA Demo</h3>

<EditForm Model="@model" OnValidSubmit="Send">
    <DataAnnotationsValidator />
    <div class="mb-3">
        <label for="name" class="form-label">Name</label>
        <input type="text" @bind="model.Name" class="form-control" id="name" name="name" />
        <ValidationMessage For="@(() => model.Name)" />
    </div>

    <div class="d-grid gap-2 col-6 mx-auto">
        <button class="btn btn-info" type="submit" disabled="@(!captchaSuccess)">Submit</button>
    </div>

    <div class="d-grid gap-2 col-6 mx-auto mt-2">
        <button class="btn btn-warning" type="button" disabled="@(!captchaSuccess)" @onclick="ResetCaptcha">Reset CAPTCHA</button>
    </div>

    <div class="d-grid gap-2 col-6 mx-auto mt-2">
        <button class="btn btn-danger" type="button" disabled="@(!captchaSuccess)" @onclick="RemoveCaptcha">Remove CAPTCHA</button>
    </div>

    <div class="d-flex justify-content-center mt-2">
        <TurstileComponent Action="SendForm"
                            Theme="TurnstileTheme.Auto"
                            Language="en-US"
                            Size="TurnstileSize.Flexible"
                            Appearance="TurnstileAppearance.Always"
                            OnSuccess="OnSuccess"
                            OnError="OnError"
                            OnExpired="OnExpired"
                            @ref="myTurnstile" />
    </div>

    <hr />

    <div class="mt-3">
        <textarea disabled class="form-control">@result</textarea>
    </div>
</EditForm>

Code Behind Example

@code {
    private TurstileComponent myTurnstile = null!;
    private bool captchaSuccess = false;
    private DemoModel model = new();
    private string result = string.Empty;

    [Inject] private GatewayTest Gateway { get; set; } = null!;

    private async Task Send()
    {
        try
        {
            await Gateway.SendAsync(model); // Send to backend
            result = "Form submitted successfully!";
        }
        catch (Exception ex)
        {
            result = ex.Message;
        }
    }

    private async Task ResetCaptcha()
    {
        captchaSuccess = false;
        model = new();
        result = null!;
        await myTurnstile.ResetAsync();
    }

    private async Task RemoveCaptcha() =>
        await myTurnstile.RemoveAsync();

    private async Task OnSuccess(string token)
    {
        captchaSuccess = true;
        model.CaptchaToken = token;
        await Task.CompletedTask;
    }

    private async Task OnError()
    {
        captchaSuccess = false;
        await Task.CompletedTask;
    }

    private async Task OnExpired()
    {
        captchaSuccess = false;
        await Task.CompletedTask;
    }
}

📜 License

MIT License


✨ Credits

Developed by Persilsoft.
For full backend support, check out Persilsoft.Turnstile.Server.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Persilsoft.Turnstile.Blazor:

Package Downloads
Persilsoft.Membership.Blazor

Contains razor clases for use in frontend membership projects

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 330 5/31/2025
1.0.0 146 5/28/2025