Chd.Library.Security 8.5.7

There is a newer version of this package available.
See the version list below for details.
dotnet add package Chd.Library.Security --version 8.5.7
                    
NuGet\Install-Package Chd.Library.Security -Version 8.5.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Chd.Library.Security" Version="8.5.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Chd.Library.Security" Version="8.5.7" />
                    
Directory.Packages.props
<PackageReference Include="Chd.Library.Security" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Chd.Library.Security --version 8.5.7
                    
#r "nuget: Chd.Library.Security, 8.5.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Chd.Library.Security@8.5.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Chd.Library.Security&version=8.5.7
                    
Install as a Cake Addin
#tool nuget:?package=Chd.Library.Security&version=8.5.7
                    
Install as a Cake Tool

Library.Security

NuGet Downloads License: MIT

Library.Security is a production-ready authentication and authorization library for .NET 8 applications. It provides JWT token management, cookie-based authentication, IP filtering middleware, and secure user login workflows—all with minimal configuration. Part of the CHD (Cleverly Handle Difficulty) ecosystem.

What Does It Do?

Library.Security provides enterprise-grade security features:

  • JWT Authentication: Symmetric & asymmetric token validation with configurable expiration
  • Cookie Authentication: Session-based auth for Razor Pages and MVC apps
  • IP Whitelisting: Middleware to restrict access by IP address
  • Secure Login: Built-in SecurityContext for user authentication workflows
  • Token Services: Generate, validate, and refresh JWT tokens
  • Integration Ready: Works seamlessly with ASP.NET Core authentication pipeline

Who Is It For?

  • ASP.NET Core Developers building secure Web APIs, Razor Pages, or MVC apps
  • Teams needing quick JWT/Cookie auth setup without boilerplate
  • Microservices requiring centralized token validation
  • Projects with IP filtering requirements (VPN, internal tools, admin panels)

📚 Table of Contents


Stop Writing Auth Boilerplate! ⏰

Every project needs authentication. Stop copy-pasting JWT configuration code. Library.Security provides production-ready auth in 3 lines.

The Problem 😫

// ❌ Every project repeats this 100+ line JWT setup:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)),
            ValidateIssuer = true,
            ValidIssuer = issuer,
            ValidateAudience = true,
            ValidAudience = audience,
            ValidateLifetime = true,
            ClockSkew = TimeSpan.Zero
        };
    });
// ... plus session config, token service, cookie setup, IP filtering...

The Solution ✅

// ✅ One line for JWT auth
builder.Services.UseJwtTokenAuthorization(builder.Configuration);

// ✅ Or one line for Cookie auth
var app = builder.UseCookieAuthorization();

// ✅ Login in 2 lines
var token = await SecurityContext.Login(this, userModel);
if (!string.IsNullOrEmpty(token)) return RedirectToAction("Dashboard");

Why Library.Security?

Problem Without Library.Security With Library.Security
JWT Setup 100+ lines of boilerplate per project 1 line: .UseJwtTokenAuthorization()
Cookie Auth Manual claims, session config, lifetime 1 line: .UseCookieAuthorization()
IP Whitelisting Custom middleware, header parsing Built-in middleware + config
Token Generation Manual JWT creation, signing, validation ITokenService with symmetric/asymmetric support
Secure Login Custom authentication logic SecurityContext.Login()
Token Refresh Complex expiration handling Auto-refresh support

Key Benefits:

  • âš¡ 90% less code - No auth boilerplate
  • 🔒 Production-tested - Used in CHD ecosystem
  • 🎨 Clean APIs - Integrates seamlessly with ASP.NET Core
  • 🛡️ Secure by default - Industry-standard JWT practices
  • 🔧 Flexible - Supports symmetric, asymmetric, and cookie auth
  • 📚 Well-documented - Real examples for every scenario

Installation

dotnet add package Chd.Library.Security

NuGet Package Manager:

Install-Package Library.Security

Package Reference (.csproj):

<PackageReference Include="Library.Security" Version="8.5.7" />

Quick Start Guide

1️⃣ JWT Authentication (Symmetric)

Step 1: Add Configuration

// appsettings.json
{
  "Jwt": {
    "Key": "YOUR_256_BIT_SECRET_KEY_MINIMUM_32_CHARACTERS_LONG!!",
    "Issuer": "https://your-auth-server.com",
    "Audience": "your-api-audience",
    "Mode": "Symmetric"
  }
}

Step 2: Configure Services

// Program.cs
var builder = WebApplication.CreateBuilder(args);

// ✅ One line JWT setup
builder.Services.UseJwtTokenAuthorization(builder.Configuration);

builder.Services.AddControllers();
var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

Step 3: Protect Your Endpoints

[ApiController]
[Route("api/[controller]")]
[Authorize] // ✅ Requires valid JWT token
public class ProductsController : ControllerBase
{
    [HttpGet]
    public IActionResult GetProducts()
    {
        return Ok(new { Message = "Secure data!" });
    }

    [HttpGet("public")]
    [AllowAnonymous] // Public endpoint
    public IActionResult GetPublicData()
    {
        return Ok(new { Message = "No auth needed" });
    }
}

2️⃣ JWT Authentication (Asymmetric - RSA)

When Your Architecture Needs Maximum Security (Microservices, Distributed Systems)

🔐 Why Asymmetric JWT?
Problem with Symmetric Asymmetric Solution
Same key signs & validates Private key signs, public key validates
Key must be shared with all services Only auth server has private key
One compromised service = system-wide breach Compromised API can't forge tokens
Single point of failure Distributed validation, centralized generation
Not suitable for public APIs Public key can be shared safely
📊 When to Use Asymmetric JWT (RSA)?
Scenario Recommendation Reason
Single monolithic app ❌ Symmetric Simpler, faster
Microservices (3+ APIs) ✅ Asymmetric Security isolation
Auth server + multiple services ✅ Asymmetric Private key stays on auth server
Third-party API integration ✅ Asymmetric Can share public key safely
High-security requirements ✅ Asymmetric No shared secrets
Public-facing APIs ✅ Asymmetric Industry standard
🚀 Quick Setup (Asymmetric)

Step 1: Generate RSA Key Pair

// Run once to generate keys
using Library.Security.Services;

TokenServicev2.GenerateRsaKeys(
    privateKeyPath: "Keys/private_key.xml",
    publicKeyPath: "Keys/public_key.xml"
);
// ⚠️ Store private key securely (Azure Key Vault, AWS Secrets Manager)
// ✅ Public key can be shared with all services

Step 2: Configuration (Auth Server - Private Key)

// appsettings.json (Auth Server only)
{
  "Jwt": {
    "Mode": "Asymmetric",
    "PrivateKeyPath": "Keys/private_key.xml",
    "PublicKeyPath": "Keys/public_key.xml",
    "Issuer": "https://auth-server.com",
    "Audience": "all-services"
  }
}

Step 3: Configuration (API Services - Public Key Only)

// appsettings.json (Catalog API, Orders API, Inventory API)
{
  "Jwt": {
    "Mode": "Asymmetric",
    "PublicKeyPath": "Keys/public_key.xml",
    "Issuer": "https://auth-server.com",
    "Audience": "all-services"
  }
}

Step 4: Enable Asymmetric JWT

// Program.cs (both Auth Server and API Services)
var builder = WebApplication.CreateBuilder(args);

// ✅ Asymmetric JWT authentication
builder.Services.UseJwtTokenAuthorizationv2(builder.Configuration);

builder.Services.AddControllers();
var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
🏗️ Real-World Architecture Example

Scenario: E-Commerce Platform with Microservices

┌─────────────────────────────────────────────────────────────┐
│                     CLIENT (Mobile/Web)                      │
└────────────────────────────┬────────────────────────────────┘
                             │
                             │ 1. Login (username/password)
                             â–¼
                ┌────────────────────────────┐
                │      AUTH SERVER           │
                │  (Private Key 🔒)          │
                │  - Validates credentials   │
                │  - Signs JWT with RSA      │
                │  - Returns token           │
                └────────────┬───────────────┘
                             │
                             │ 2. JWT Token
                             â–¼
                ┌────────────────────────────┐
                │         CLIENT             │
                │  Stores token              │
                └────────────┬───────────────┘
                             │
                             │ 3. API Requests with JWT
           ┌─────────────────┼─────────────────┐
           │                 │                 │
           â–¼                 â–¼                 â–¼
  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐
  │ CATALOG API │   │ ORDERS API  │   │ PAYMENT API │
  │ (Public Key)│   │ (Public Key)│   │ (Public Key)│
  │ ✅ Validates│   │ ✅ Validates│   │ ✅ Validates│
  │ ❌ Can't    │   │ ❌ Can't    │   │ ❌ Can't    │
  │    forge    │   │    forge    │   │    forge    │
  └─────────────┘   └─────────────┘   └─────────────┘
💻 Complete Code Example

Auth Server (Token Generation with Private Key):

// Controllers/AuthController.cs (Auth Server)
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly ITokenService _tokenService; // TokenServicev2 for asymmetric
    private readonly UserService _userService;

    public AuthController(ITokenService tokenService, UserService userService)
    {
        _tokenService = tokenService;
        _userService = userService;
    }

    [HttpPost("login")]
    [AllowAnonymous]
    public IActionResult Login([FromBody] UserModel model)
    {
        // Validate credentials
        var user = _userService.ValidateUser(model.UserName, model.Password);
        if (user == null)
            return Unauthorized(new { Message = "Invalid credentials" });

        // ✅ Generate JWT using RSA private key
        var token = _tokenService.BuildToken(new UserDTO
        {
            UserId = user.Id,
            UserName = user.Username,
            Role = user.Role
        });

        return Ok(new
        {
            Token = token,
            ExpiresIn = 3600, // 1 hour
            TokenType = "Bearer"
        });
    }
}

Catalog API (Token Validation with Public Key):

// Controllers/ProductsController.cs (Catalog API)
[ApiController]
[Route("api/[controller]")]
[Authorize] // ✅ Validates token with public key (can't forge tokens)
public class ProductsController : ControllerBase
{
    private readonly IProductService _productService;

    [HttpGet("{id}")]
    public IActionResult GetProduct(int id)
    {
        // Token validated by middleware using public key
        var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        var role = User.FindFirst(ClaimTypes.Role)?.Value;

        var product = _productService.GetProduct(id);
        return Ok(product);
    }
}

Orders API (Also Validates with Public Key):

// Controllers/OrdersController.cs (Orders API)
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class OrdersController : ControllerBase
{
    [HttpPost]
    public IActionResult CreateOrder([FromBody] OrderRequest request)
    {
        // ✅ Same token works across all services
        // ✅ Each service validates independently with public key
        // ❌ Compromised service can't create fake tokens

        var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;

        // Create order logic...
        return Ok(new { OrderId = 12345 });
    }
}
🔒 Security Benefits
Aspect Symmetric (Shared Secret) Asymmetric (RSA)
Key Distribution All services need secret key Only public key distributed
Breach Impact One compromised service = all tokens can be forged Compromised service can't forge tokens
Key Rotation Update all services simultaneously Update only auth server, APIs auto-refresh
Third-Party Access Can't share key safely Can share public key with partners
Compliance Basic security Meets PCI-DSS, HIPAA, SOC2
🎯 Best Practices for Asymmetric JWT
  1. ✅ Store Private Key Securely

    // ❌ NEVER commit private key to source control
    // ✅ Use Azure Key Vault
    var keyVaultUrl = "https://your-vault.vault.azure.net/";
    var privateKey = await keyVaultClient.GetSecretAsync(keyVaultUrl, "jwt-private-key");
    
    // ✅ Or environment variable
    var privateKey = Environment.GetEnvironmentVariable("JWT_PRIVATE_KEY");
    
  2. ✅ Rotate Keys Regularly

    // Generate new key pair every 90 days
    TokenServicev2.GenerateRsaKeys(
        "Keys/private_key_v2.xml",
        "Keys/public_key_v2.xml"
    );
    // Support both old and new keys during transition
    
  3. ✅ Use Strong Key Size

    // Minimum 2048-bit RSA keys (default in TokenServicev2)
    // For high security: 4096-bit
    
  4. ✅ Implement Key Versioning

    {
      "Jwt": {
        "Keys": [
          { "Version": "v2", "PublicKeyPath": "Keys/public_key_v2.xml" },
          { "Version": "v1", "PublicKeyPath": "Keys/public_key_v1.xml" }
        ]
      }
    }
    
âš¡ Performance Consideration
Operation Symmetric (HS256) Asymmetric (RS256)
Token Generation ~0.1 ms ~2 ms
Token Validation ~0.1 ms ~0.5 ms
Verdict Faster Slightly slower, but negligible in most apps

💡 Recommendation: Use asymmetric JWT for microservices despite 20x slower generation—security benefits outweigh 2ms overhead.


Perfect for Razor Pages apps with server-side rendering:

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

// ✅ Cookie authentication with one line
var app = builder.UseCookieAuthorization();

app.MapRazorPages();
app.Run();

appsettings.json:

{
  "SecurityConfig": {
    "Issuer": "https://your-app.com",
    "Audience": "your-app-users",
    "Key": "YOUR_SECRET_KEY"
  }
}

Login Page Example:

// Pages/Login.cshtml.cs
public class LoginModel : PageModel
{
    [BindProperty]
    public string Username { get; set; }
    
    [BindProperty]
    public string Password { get; set; }
    
    public async Task<IActionResult> OnPostAsync()
    {
        var userModel = new UserModel
        {
            UserName = Username,
            Password = Password.ToMd5() // Hash password
        };
        
        // ✅ Built-in secure login
        bool success = await SecurityContext.LoginCookieAuthentitation(
            this, 
            userModel, 
            ValidateUser // Your validation function
        );
        
        if (success)
            return RedirectToPage("/Dashboard");
        else
            return Page(); // Show error
    }
    
    private UserDTO ValidateUser(UserModel model)
    {
        // Your database validation logic
        var user = _db.Users.FirstOrDefault(u => 
            u.Username == model.UserName && 
            u.PasswordHash == model.Password);
        
        if (user == null) return null;
        
        return new UserDTO
        {
            UserId = user.Id,
            UserName = user.Username,
            Role = user.Role
        };
    }
}

4️⃣ IP Whitelisting Middleware

Restrict access to specific IP addresses (VPN, internal tools, admin panels):

Step 1: Configuration

// appsettings.json
{
  "AllowedIPs": [
    "192.168.1.100",
    "10.0.0.50",
    "203.0.113.42"
  ]
}

Step 2: Enable Middleware

// Program.cs
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// ✅ IP filtering middleware
app.UseIpFilterMiddleware();

app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

Features:

  • ✅ Handles X-Forwarded-For header (proxies, load balancers)
  • ✅ 20-second cache for performance
  • ✅ Returns 403 Forbidden for blocked IPs
  • ✅ Whitelist reloads automatically

5️⃣ Secure Login with SecurityContext

For Web APIs with external token generation service:

[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    [HttpPost("login")]
    [AllowAnonymous]
    public async Task<IActionResult> Login([FromBody] UserModel userModel)
    {
        // Hash password before validation
        userModel.Password = userModel.Password?.ToMd5();
        
        // ✅ SecurityContext handles token generation via external service
        var token = await SecurityContext.Login(this, userModel);
        
        if (string.IsNullOrEmpty(token))
        {
            return Unauthorized(new { Message = "Invalid credentials" });
        }
        
        // Token stored in session automatically
        return Ok(new
        {
            Token = token,
            ExpiresIn = 3600 // 1 hour
        });
    }
}

How It Works:

  1. SecurityContext.Login() posts credentials to Jwt:Issuer URL (your token service)
  2. Token service validates user and generates JWT
  3. Token stored in HttpContext.Session["Token"]
  4. Returns token for client storage (localStorage, cookie, etc.)

Configuration Reference

JWT Configuration (Symmetric)

{
  "Jwt": {
    "Key": "YOUR_MINIMUM_32_CHARACTER_SECRET_KEY",
    "Issuer": "https://your-auth-server.com",
    "Audience": "your-api-name",
    "Mode": "Symmetric"
  }
}
Property Required Description
Key ✅ Yes Secret key for signing tokens (min 32 chars for HS256)
Issuer ✅ Yes Token issuer URL (your auth server)
Audience ✅ Yes Token audience (your API name)
Mode ❌ No "Symmetric" (default) or "Asymmetric"

JWT Configuration (Asymmetric - RSA)

{
  "Jwt": {
    "Mode": "Asymmetric",
    "PublicKeyPath": "Keys/public_key.xml",
    "PrivateKeyPath": "Keys/private_key.xml",
    "Issuer": "https://your-auth-server.com",
    "Audience": "your-api-name"
  }
}

Generate RSA Keys:

TokenServicev2.GenerateRsaKeys("Keys/private_key.xml", "Keys/public_key.xml");

{
  "SecurityConfig": {
    "Issuer": "https://your-app.com",
    "Audience": "your-app-users",
    "Key": "YOUR_SECRET_KEY"
  }
}

Cookie Options (automatic):

  • Expiration: 20 minutes (sliding)
  • SameSite: Strict
  • HttpOnly: true
  • AccessDeniedPath: /Forbidden/

IP Whitelist Configuration

{
  "AllowedIPs": [
    "192.168.1.0/24",
    "10.0.0.50",
    "203.0.113.42"
  ]
}

Cache: 20 seconds (auto-reload)


Real-World Examples

// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.UseCookieAuthorization(); // ✅ Cookie auth
app.MapRazorPages();
app.Run();

// Pages/Account/Login.cshtml.cs
public class LoginModel : PageModel
{
    private readonly ShopDbContext _db;
    
    public LoginModel(ShopDbContext db) => _db = db;
    
    [BindProperty]
    public string Email { get; set; }
    
    [BindProperty]
    public string Password { get; set; }
    
    public async Task<IActionResult> OnPostAsync()
    {
        var userModel = new UserModel
        {
            UserName = Email,
            Password = Password.ToMd5()
        };
        
        // ✅ Secure login with cookie
        bool success = await SecurityContext.LoginCookieAuthentitation(
            this, 
            userModel, 
            user =>
            {
                var dbUser = _db.Users.FirstOrDefault(u => 
                    u.Email == user.UserName && 
                    u.PasswordHash == user.Password);
                
                if (dbUser == null) return null;
                
                return new UserDTO
                {
                    UserId = dbUser.Id,
                    UserName = dbUser.Email,
                    Role = dbUser.Role
                };
            }
        );
        
        if (success)
            return RedirectToPage("/Dashboard");
        
        ModelState.AddModelError("", "Invalid email or password");
        return Page();
    }
}

// Pages/Dashboard.cshtml.cs
[Authorize] // ✅ Requires authentication
public class DashboardModel : PageModel
{
    public string Username => User.Identity?.Name ?? "Guest";
    
    public void OnGet()
    {
        // User is authenticated
    }
}

Example 2: Web API with JWT + IP Filtering

// Program.cs
var builder = WebApplication.CreateBuilder(args);

// ✅ JWT authentication
builder.Services.UseJwtTokenAuthorization(builder.Configuration);
builder.Services.AddControllers();

var app = builder.Build();

// ✅ IP filtering for admin routes
app.UseWhen(
    context => context.Request.Path.StartsWithSegments("/api/admin"),
    appBuilder => appBuilder.UseIpFilterMiddleware()
);

app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

// Controllers/AdminController.cs
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class AdminController : ControllerBase
{
    // ✅ Only accessible from whitelisted IPs
    [HttpGet("users")]
    public IActionResult GetUsers()
    {
        return Ok(new { Message = "Admin data" });
    }
}

Example 3: Microservices with Centralized Auth

// Auth Service (Token Generation)
[HttpPost("token")]
public IActionResult GenerateToken([FromBody] UserModel model)
{
    var user = ValidateUser(model);
    if (user == null) return Unauthorized();
    
    var token = _tokenService.BuildToken(user);
    return Ok(new { Token = token });
}

// Product Service (Token Validation)
var builder = WebApplication.CreateBuilder(args);

// ✅ Validate tokens from Auth Service
builder.Services.UseJwtTokenAuthorization(builder.Configuration);

// appsettings.json in Product Service
{
  "Jwt": {
    "Issuer": "https://auth-service.com", // ✅ Same issuer
    "Audience": "product-service",
    "Key": "SHARED_SECRET_KEY" // ✅ Same key
  }
}

API Reference

Extension Methods

IServiceCollection Extensions
// JWT authentication (symmetric)
services.UseJwtTokenAuthorization(configuration);

// JWT authentication (asymmetric RSA)
services.UseJwtTokenAuthorizationv2(configuration);

// Cookie authentication
var app = builder.UseCookieAuthorization();

SecurityContext Class

// JWT login (calls external token service)
Task<string> SecurityContext.Login(
    ControllerBase controller, 
    UserModel userModel
)

// Cookie login (local validation)
Task<bool> SecurityContext.LoginCookieAuthentitation(
    Controller controller,
    UserModel userModel,
    Func<UserModel, UserDTO> validationFunc
)

ITokenService Interface

public interface ITokenService
{
    string BuildToken(UserDTO user);
    bool ValidateToken(string token);
    ClaimsPrincipal GetPrincipalFromToken(string token);
}

Models

public class UserModel
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

public class UserDTO
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string Role { get; set; }
}

public class SecurityConfig
{
    public string Issuer { get; set; }
    public string Audience { get; set; }
    public string Key { get; set; }
}

Security Best Practices

  1. ✅ Use HTTPS only - JWT tokens are vulnerable to interception
  2. ✅ Store keys in environment variables - Never commit secrets to source control
  3. ✅ Rotate keys regularly - Update Jwt:Key every 90 days
  4. ✅ Use asymmetric keys for microservices - Private key only on auth service
  5. ✅ Hash passwords - Use .ToMd5() or better: BCrypt, PBKDF2
  6. ✅ Set short token lifetimes - 15-60 minutes for sensitive APIs
  7. ✅ Implement refresh tokens - For long-lived sessions
  8. ⚠️ Don't use MD5 for production passwords - Use ASP.NET Core Identity or BCrypt

Troubleshooting

Issue: 401 Unauthorized even with valid token

Cause: Issuer/Audience mismatch or expired token

Fix:

// Check token validation parameters
options.TokenValidationParameters = new TokenValidationParameters
{
    ValidateIssuer = true,
    ValidIssuer = "YOUR_ISSUER", // ✅ Must match token's "iss" claim
    ValidateAudience = true,
    ValidAudience = "YOUR_AUDIENCE", // ✅ Must match token's "aud" claim
    ValidateLifetime = true // ✅ Checks "exp" claim
};

Issue: IP filtering blocks legitimate users

Cause: Proxy/load balancer not forwarding real client IP

Fix:

// Enable X-Forwarded-For header forwarding
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

// BEFORE IP filter middleware
app.UseIpFilterMiddleware();

Issue: "Key length is too short" error

Cause: JWT key must be at least 256 bits (32 characters) for HS256

Fix:

{
  "Jwt": {
    "Key": "THIS_IS_A_VERY_LONG_SECRET_KEY_AT_LEAST_32_CHARS_123456!"
  }
}

FAQ

Scenario Recommendation
Web API (mobile/SPA clients) JWT
Razor Pages / MVC (server-side) Cookie
Microservices JWT
Internal admin tools Cookie + IP filtering

2. How do I refresh expired tokens?

Implement refresh token logic in your token service:

[HttpPost("refresh")]
public IActionResult RefreshToken([FromBody] string refreshToken)
{
    var user = ValidateRefreshToken(refreshToken);
    if (user == null) return Unauthorized();
    
    var newToken = _tokenService.BuildToken(user);
    return Ok(new { Token = newToken });
}

Yes! Use JWT for API endpoints and Cookie for Razor Pages:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options => { /* JWT config */ })
    .AddCookie(options => { /* Cookie config */ });

// Apply [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
// to API controllers

4. Is MD5 secure for password hashing?

No! MD5 is deprecated. Use:

  • BCrypt (recommended): BCrypt.Net.HashPassword(password)
  • ASP.NET Core Identity (built-in): Handles hashing + salting automatically

Package Description NuGet
Chd.Common Infrastructure primitives (encryption, config, extensions) NuGet
Chd.Min.IO MinIO/S3 object storage with image optimization NuGet
Chd.Logging Structured logging with Serilog (Graylog, MSSQL, file sinks) NuGet
Chd.Caching Redis distributed caching with AOP attributes NuGet

Contributing 🤝

Found a security vulnerability? Please do not open a public issue. Email security@chd.dev instead.

For feature requests:

  1. Issues: GitHub Issues
  2. Pull Requests: GitHub PRs

Authors

See also contributors on NuGet


License 📜

This package is free and open-source under the MIT License.


Made with ❤️ by the CHD Team
Cleverly Handle Difficulty 🔐

Product 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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
8.6.0 0 3/2/2026
8.5.9 0 3/2/2026
8.5.7 0 3/2/2026
8.5.6 86 2/19/2026
8.5.5 90 1/15/2026
8.5.3 94 1/12/2026
8.5.2 152 7/31/2025
8.5.1 569 7/23/2025
8.0.3 155 12/23/2024
Loading failed