Persilsoft.Turnstile.Blazor
1.0.2
See the version list below for details.
dotnet add package Persilsoft.Turnstile.Blazor --version 1.0.2
NuGet\Install-Package Persilsoft.Turnstile.Blazor -Version 1.0.2
<PackageReference Include="Persilsoft.Turnstile.Blazor" Version="1.0.2" />
<PackageVersion Include="Persilsoft.Turnstile.Blazor" Version="1.0.2" />
<PackageReference Include="Persilsoft.Turnstile.Blazor" />
paket add Persilsoft.Turnstile.Blazor --version 1.0.2
#r "nuget: Persilsoft.Turnstile.Blazor, 1.0.2"
#:package Persilsoft.Turnstile.Blazor@1.0.2
#addin nuget:?package=Persilsoft.Turnstile.Blazor&version=1.0.2
#tool nuget:?package=Persilsoft.Turnstile.Blazor&version=1.0.2
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
- Install the NuGet package:
dotnet add package Persilsoft.Turnstile.Blazor
- 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/siteverifyAPI 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 | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- Microsoft.AspNetCore.Components.Web (>= 10.0.0)
- Microsoft.Extensions.Http (>= 10.0.0)
- Persilsoft.Blazor.JSInterop (>= 1.0.14)
- Persilsoft.Turnstile.Shared (>= 1.0.2)
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.