C# .NET 10.0 Blazor Server component for hCaptcha.
Warning
This library is designed for Blazor Server with interactive rendering enabled. It does NOT support Blazor WebAssembly.
- .NET 10.0
- Blazor Server with interactive rendering (
@rendermode InteractiveServer) - hCaptcha site key and secret
- Client access to
https://js.hcaptcha.com/1/api.js - Server access to
https://hcaptcha.com/siteverify
dotnet add package ChatAIze.CaptchaInstall-Package ChatAIze.Captcha// Program.cs
builder.Services.AddCaptcha(o =>
{
o.SiteKey = builder.Configuration["Captcha:SiteKey"]!;
o.Secret = builder.Configuration["Captcha:Secret"]!;
});
app.UseCaptcha();
// App.razor (or index.html)
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
// Any .razor component
@rendermode InteractiveServer
<Captcha @bind-IsVerified="_isVerified" />
@code {
private bool _isVerified;
}
builder.Services.AddCaptcha(o =>
{
o.SiteKey = builder.Configuration["Captcha:SiteKey"]!;
o.Secret = builder.Configuration["Captcha:Secret"]!;
o.VerifyIpAddresses = false; // optional, default is false
o.IsConnectionProxied = false; // optional, default is false
});Note
If users connect through a reverse proxy (Cloudflare, Nginx, etc.), set IsConnectionProxied = true
and ensure your proxy is configured to send a trusted X-Forwarded-For header.
{
"Captcha": {
"SiteKey": "YOUR_SITE_KEY",
"Secret": "YOUR_SECRET"
}
}# Prefer environment variables for secrets in production
Captcha__SiteKey=YOUR_SITE_KEY
Captcha__Secret=YOUR_SECRETapp.UseCaptcha();Note
If you use UseForwardedHeaders, call it before UseCaptcha() so the IP is already resolved.
app.UseForwardedHeaders();
app.UseCaptcha();Docs: https://learn.microsoft.com/aspnet/core/host-and-deploy/proxy-load-balancer
<head>
<!-- ... -->
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
<!-- ... -->
</head>@using ChatAIze.Captcha@rendermode InteractiveServer
<Captcha @bind-IsVerified="_isVerified" />
<p>Verified: @_isVerified</p>
@code {
private bool _isVerified;
}<Captcha
@bind-IsVerified="_isVerified"
Succeeded="OnSucceeded"
Expired="OnExpired"
Error="OnError" />
@code {
private bool _isVerified;
private void OnSucceeded() { }
private void OnExpired() { }
private void OnError(string code) { }
}<Captcha
@bind-IsVerified="_isVerified"
SiteKey="YOUR_SITE_KEY"
Secret="YOUR_SECRET" /><Captcha
@bind-IsVerified="_isVerified"
Theme="CaptchaTheme.Auto"
Size="CaptchaSize.Normal" />builder.Services.AddCaptcha(o =>
{
o.SiteKey = "...";
o.Secret = "...";
o.VerifyIpAddresses = true;
o.IsConnectionProxied = true; // set to true if behind a proxy
});Warning
Only enable IP verification if you understand the privacy implications and your proxy setup is trusted.
- Never expose
Secretto the client; it must stay server-side. - Treat IP verification as personal data processing where applicable.
- If you use a proxy, ensure
X-Forwarded-Foris trusted and not spoofable. - Re-check
IsVerifiedon the server before sensitive operations.
- Ensure CSP allows
https://js.hcaptcha.comand hCaptcha-related endpoints. - hCaptcha CSP guidance: https://docs.hcaptcha.com/configuration#content-security-policy-csp
CaptchaOptions
SiteKey(required): hCaptcha site key.Secret(required): hCaptcha secret key.VerifyIpAddresses(optional): Include client IPs in verification requests.IsConnectionProxied(optional): Read IPs fromX-Forwarded-Forwhen behind a proxy.
Captcha
IpAddress: Optional IP override for verification.SiteKey: Optional site key override.Secret: Optional secret override.Theme:Auto,Light,Dark.Size:Normal,Compact.IsVerified: Two-way bound verification state.- Events:
Opened,Closed,Succeeded,Expired,ChallengeExpired,Error.
- Gate sensitive actions on
IsVerifiedand re-check before processing server actions. - Keep
Secreton the server only; never expose it to client code. - Use
VerifyIpAddressesonly when required by your security policy. - If proxied, ensure
X-Forwarded-Forcomes from a trusted source and is properly configured. - Handle
ExpiredandErrorto prompt users to retry. - Add rate limiting on endpoints that are protected by CAPTCHA to reduce abuse.
- Blazor WebAssembly is not supported.
- JavaScript is required; the widget will not render without
api.js. - Interactive rendering is required; static rendering alone is not enough.
- Blazor WebAssembly is not supported.
X-Forwarded-Foris used as-is when proxied; if multiple IPs are present, configure your proxy to send a single, trusted client IP.
- Widget does not render: Ensure
api.jsis included and the component uses interactive rendering. - Always fails verification: Check that
SiteKeyandSecretmatch your hCaptcha settings and that the server can reachhttps://hcaptcha.com/siteverify. - script-error / script blocked: The hCaptcha JS SDK is blocked (corporate firewall, ad blocker, or CSP).
- Errors after proxying: Confirm
X-Forwarded-Foris trustworthy and not being overwritten by untrusted clients.
| Code | Description |
|---|---|
| rate-limited | User has sent too many requests |
| network-error | There are network connection issues (e.g., offline). hCaptcha will automatically retry. |
| invalid-data | Invalid data is not accepted by endpoints |
| challenge-error | Challenge encountered error on setup. User may need to select the checkbox or call execute. |
| challenge-closed | User closed the challenge |
| challenge-expired | Time limit to answer challenge has expired |
| missing-captcha | No captcha was found. Verify hCaptcha was properly setup and a captcha was rendered. |
| invalid-captcha-id | Captcha does not exist for ID provided. Check that the captcha rendered matches the stored ID. |
| internal-error | hCaptcha client encountered an internal error. User may need to select the checkbox or call execute. |
| script-error | hCaptcha JS SDK could not be loaded. User may be behind a firewall blocking api.js. |
Source: https://docs.hcaptcha.com/configuration#error-codes
- GitHub: https://github.com/chataize/captcha
- Chataize organization: https://github.com/chataize
- Website: https://www.chataize.com