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
<PackageReference Include="Persilsoft.Turnstile.Blazor" Version="1.0.1" />
<PackageVersion Include="Persilsoft.Turnstile.Blazor" Version="1.0.1" />
<PackageReference Include="Persilsoft.Turnstile.Blazor" />
paket add Persilsoft.Turnstile.Blazor --version 1.0.1
#r "nuget: Persilsoft.Turnstile.Blazor, 1.0.1"
#:package Persilsoft.Turnstile.Blazor@1.0.1
#addin nuget:?package=Persilsoft.Turnstile.Blazor&version=1.0.1
#tool nuget:?package=Persilsoft.Turnstile.Blazor&version=1.0.1
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/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 | Versions 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. |
-
net9.0
- Microsoft.AspNetCore.Components.Web (= 9.0.4)
- Microsoft.Extensions.Http (= 9.0.4)
- Persilsoft.Blazor.JSInterop (= 1.0.12)
- Persilsoft.HttpDelegatingHandlers (= 1.0.20)
- Persilsoft.Turnstile.Shared (= 1.0.1)
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.