Sj.Captcha
0.1.0
dotnet add package Sj.Captcha --version 0.1.0
NuGet\Install-Package Sj.Captcha -Version 0.1.0
<PackageReference Include="Sj.Captcha" Version="0.1.0" />
<PackageVersion Include="Sj.Captcha" Version="0.1.0" />
<PackageReference Include="Sj.Captcha" />
paket add Sj.Captcha --version 0.1.0
#r "nuget: Sj.Captcha, 0.1.0"
#:package Sj.Captcha@0.1.0
#addin nuget:?package=Sj.Captcha&version=0.1.0
#tool nuget:?package=Sj.Captcha&version=0.1.0
Sj.Captcha
Self-hosted Proof-of-Work CAPTCHA for ASP.NET Core. The package is designed for Linux and Docker deployments, with no external CAPTCHA provider, native dependency, or third-party runtime API dependency.
Repository: https://github.com/SjCaptcha/SjCaptcha
Architecture
The solution is intentionally scaffolded without CAPTCHA business logic.
Abstractions: public contracts for challenge generation, verification, storage, and integration points.Configuration: options and validation for application-controlled policy.Models: request, challenge, verification, and result models.Security: cryptographic primitives, token protection, replay prevention, and security policy implementation.Services: orchestration and Proof-of-Work services behind the public contracts.Storage: storage contracts and provider implementations; the core package should support an in-memory baseline and allow distributed stores through abstractions.Middleware: ASP.NET Core request pipeline integration.Endpoints: minimal API endpoint registration and HTTP handlers.TagHelpers: optional Razor Tag Helpers for server-rendered forms.Extensions: dependency injection and application builder extension methods.wwwroot: browser assets shipped by the library, kept dependency-free.
The library targets net8.0, net9.0, and net10.0, and uses the ASP.NET Core shared framework. The sample targets .NET 10. Tests run against all three supported target frameworks.
Security direction
Proof-of-Work challenges should be bound to a short-lived, integrity-protected server token and verified server-side with constant-time comparisons where applicable. Challenge issuance, verification, expiration, replay protection, request throttling, and storage are separate concerns so deployments can choose an appropriate local or distributed strategy.
Phase 1 contains the configuration, defaults, constants, and domain contracts. Phase 2 adds security components. Phase 3 adds the asynchronous core service for challenge creation and verification. Phase 4 adds ASP.NET Core middleware and endpoint routing integration. Optional distributed storage is available from the separate Sj.Captcha.Redis package; the core package has no Redis dependency.
Rate limiting is applied to both CAPTCHA routes by AddSjCaptcha. Client binding, enabled by default, stores one-way SHA-256 hashes of the request IP, User-Agent, and available session identifier. CaptchaCleanupHostedService removes expired records from stores that support explicit cleanup; Redis records use distributed-cache TTL expiration.
ASP.NET Core integration
Register the core service and automatic routes:
builder.Services.AddSjCaptcha(options =>
{
options.Difficulty = 5;
options.SecretKey = "YOUR_SECRET";
});
app.UseSjCaptcha();
This exposes GET /sj-captcha/challenge and POST /sj-captcha/verify. Applications using explicit endpoint routing can call app.MapSjCaptchaEndpoints() instead of app.UseSjCaptcha().
Redis storage
Install Sj.Captcha.Redis only when distributed challenge storage is required:
builder.Services.AddSjCaptchaRedis(builder.Configuration);
The optional integration uses IDistributedCache, stores challenges as JSON with absolute expiration, and reads ConnectionStrings:Redis or SjCaptcha:Redis:ConnectionString.
Browser client
The core package includes the dependency-free client at _content/Sj.Captcha/sjcaptcha.js:
<script src="/_content/Sj.Captcha/sjcaptcha.js"></script>
<script>
const captcha = new SjCaptchaClient({ timeout: 30000 });
captcha.run().then(function (result) {
if (result.verification.succeeded) {
// Continue the protected workflow.
}
});
</script>
Call captcha.cancel() to stop an active operation, or pass an AbortSignal to run({ signal }).
Razor TagHelper
For MVC and Razor Pages, register the package TagHelper in _ViewImports.cshtml:
@addTagHelper *, Sj.Captcha
Then use either element name:
<sj-captcha difficulty="6" theme="dark" />
<pow-captcha />
Build
dotnet build Sj.Captcha.sln
dotnet test Sj.Captcha.sln
dotnet pack Sj.Captcha/Sj.Captcha.csproj --configuration Release
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. 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 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
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 138 | 8/25/2026 |
Initial public release.