Xylocopadream.Otp.Authenticate.Domain
0.1.0
Prefix Reserved
dotnet add package Xylocopadream.Otp.Authenticate.Domain --version 0.1.0
NuGet\Install-Package Xylocopadream.Otp.Authenticate.Domain -Version 0.1.0
<PackageReference Include="Xylocopadream.Otp.Authenticate.Domain" Version="0.1.0" />
<PackageVersion Include="Xylocopadream.Otp.Authenticate.Domain" Version="0.1.0" />
<PackageReference Include="Xylocopadream.Otp.Authenticate.Domain" />
paket add Xylocopadream.Otp.Authenticate.Domain --version 0.1.0
#r "nuget: Xylocopadream.Otp.Authenticate.Domain, 0.1.0"
#:package Xylocopadream.Otp.Authenticate.Domain@0.1.0
#addin nuget:?package=Xylocopadream.Otp.Authenticate.Domain&version=0.1.0
#tool nuget:?package=Xylocopadream.Otp.Authenticate.Domain&version=0.1.0
Xylocopadream.Otp.Authenticate
Passwordless OTP authentication server for ASP.NET Core: the user receives a code by e-mail, exchanges it for a JWT (identity claims only) and a refresh token.
| Package | Layer |
|---|---|
Xylocopadream.Otp.Authenticate.Domain |
Entities and models |
Xylocopadream.Otp.Authenticate.Application |
Use cases, JWT issuing, e-mail, Minimal API endpoints |
Xylocopadream.Otp.Authenticate.Infrastructure |
EF Core + ASP.NET Identity persistence |
Xylocopadream.Otp.Authenticate.Server |
One-call registration in a host |
Xylocopadream.Otp.AspNetCore.Infrastructure |
X-Correlation-Id middleware |
Usage
builder.Services.AddAuthenticationServerDI(
builder.Configuration,
options => options.UseSqlite("Data Source=app.db"));
var app = builder.Build();
app.UseAuthenticationActivated() // UseAuthentication + UseAuthorization + UseRateLimiter
.UseCorrelationId();
app.MapAuthEndpoints<Program>(); // POST /auth/register, request-code, verify-code, refresh, logout
// GET /.well-known/openid-configuration, /.well-known/jwks.json
Security
- OTP codes: cryptographically random, stored as HMAC-SHA256 (key derived from
JwtSettings:SigningKey), valid 5 minutes, 5 attempts consumed atomically. - Per email: at most one code per minute and 5 codes per hour (HTTP 429).
- Per client IP: 20 requests per minute on the
/authendpoints (HTTP 429). Behind a reverse proxy, configureForwardedHeadersso the real client IP is used. - Refresh tokens: stored as SHA-256 hashes, rotated atomically on each use. Presenting an already rotated token revokes every session of the user (theft detection).
- Expired data is purged every
Otp:PurgeInterval(and at startup): OTP codes older than one hour, refresh tokens past their expiry. Revoked tokens are kept until they expire, so a replayed stolen token is still detected. - Access tokens: signed with ES256 (ECDSA P-256). Only the OTP server holds the private key; consuming services validate with the public keys published at
/.well-known/jwks.json(discovery:/.well-known/openid-configuration), so they cannot issue tokens. Only ES256 is accepted (nonone, no HS256 confusion). - One audience per service: the client names the service it asks tokens for (
audienceinPOST /auth/verify-code), which must be listed inJwtSettings:Audiences; each service only accepts its own tokens. The refresh token keeps its audience, and removing a service from the list ends its sessions at their next renewal.
Key rotation: move the current key to
JwtSettings:PreviousSigningKeys, set the new one inJwtSettings:SigningKey, restart. Services fetch the new key on the unknownkid; remove the old key onceAccessTokenLifetimehas elapsed. Pending OTP codes are invalidated (their HMAC key is derived from the signing key).
Configuration
Only JwtSettings:SigningKey, Issuer, Audiences, EmailSettings and Administration:Email are required; the values below are the defaults.
Create the signing key (ECDSA P-256, PEM) and keep it out of the repository:
key="$(openssl ecparam -name prime256v1 -genkey | openssl pkcs8 -topk8 -nocrypt)"
dotnet user-secrets set "JwtSettings:SigningKey" "$key"
{
"JwtSettings": {
"SigningKey": "-----BEGIN PRIVATE KEY-----\n...", "PreviousSigningKeys": [],
"Issuer": "https://otp.example.com", "Audiences": [ "xylocopa", "billing-api" ],
"AccessTokenLifetime": "00:15:00", "RefreshTokenLifetime": "30.00:00:00"
},
"Otp": {
"CodeLifetime": "00:05:00", "MaxAttempts": 5,
"MinDelayBetweenCodes": "00:01:00", "MaxCodesPerHour": 5,
"RequestsPerMinutePerIp": 20,
"PurgeInterval": "01:00:00"
},
"EmailSettings": { "Host": "smtp.example.com", "Port": 587, "Username": "", "Password": "", "FromEmail": "no-reply@example.com", "FromName": "OTP" },
"Administration": { "Email": "admin@example.com" }
}
License
AGPL-3.0-or-later. If you run a modified version as a network service, you must offer its source code to its users.
| 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
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Xylocopadream.Otp.Authenticate.Domain:
| Package | Downloads |
|---|---|
|
Xylocopadream.Otp.Authenticate.Application
Use cases of the Xylocopadream OTP authentication server: OTP codes, JWT issuing, refresh tokens and user administration. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 50 | 10/7/2026 |