Tooark.Securities 4.2.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package Tooark.Securities --version 4.2.1
                    
NuGet\Install-Package Tooark.Securities -Version 4.2.1
                    
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="Tooark.Securities" Version="4.2.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Tooark.Securities" Version="4.2.1" />
                    
Directory.Packages.props
<PackageReference Include="Tooark.Securities" />
                    
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 Tooark.Securities --version 4.2.1
                    
#r "nuget: Tooark.Securities, 4.2.1"
                    
#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 Tooark.Securities@4.2.1
                    
#: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=Tooark.Securities&version=4.2.1
                    
Install as a Cake Addin
#tool nuget:?package=Tooark.Securities&version=4.2.1
                    
Install as a Cake Tool

Tooark.Securities

Security library for .NET applications, providing AES cryptography and JWT authentication services with support for multiple algorithms.

🌍 Languages: πŸ‡ΊπŸ‡Έ English (this file) Β· πŸ‡§πŸ‡· PortuguΓͺs

πŸ“¦ Package Contents

Services

Class Description
JwtTokenService Service for creating and validating JWT tokens
CryptographyService AES-256 encryption/decryption service

Interfaces

Interface Description
IJwtTokenService Contract for handling JWT tokens
ICryptographyService Contract for AES encryption/decryption
Member Description
IJwtTokenService.Create Creates the token. Synchronous: the handler exposes no async creation
IJwtTokenService.ValidateAsync Validates the token. Direct path to the handler, which is asynchronous
IJwtTokenService.Validate Validates the token. Synchronous wrapper of ValidateAsync
ICryptographyService.Encrypt Encrypts. Synchronous: in-memory AES, no I/O
ICryptographyService.Decrypt Decrypts. Synchronous, for the same reason

DTOs

Class Description
JwtTokenDto Data for creating a token (id, login, security)
UserTokenDto Result of the token validation

Options

Class Description
JwtOptions JWT settings (algorithm, keys, issuer(s), audience(s), expiration)
CryptographyOptions Cryptography settings (algorithm, secret or secretBase64)

Extensions

Class Description
RoleClaimsExtension Extension that converts JwtTokenDto into claims (id, login, security)

πŸ”§ Installation

dotnet add package Tooark.Securities

βš™οΈ Configuration

appsettings.json

To configure the security services, add the Jwt and Cryptography sections to your appsettings.json:

Example configuration for a JWT token with symmetric algorithms (uses Secret for signing and validation):

{
  "Jwt": {
    "Algorithm": "HS256",
    "Secret": "your-secret-key-with-at-least-32-characters",
    "Issuer": "your-application",
    "Audience": "your-clients",
    "ExpirationTime": 60
  }
}

Example configuration for a JWT token with asymmetric algorithms (PrivateKey required for signing, PublicKey required for validation):

{
  "Jwt": {
    "Algorithm": "RS256",
    "PrivateKey": "your-private-key-in-base64",
    "PublicKey": "your-public-key-in-base64",
    "Issuer": "your-application",
    "Audience": "your-clients",
    "ExpirationTime": 60
  }
}

Example configuration for AES cryptography:

{
  "Cryptography": {
    "Algorithm": "GCM",
    "Secret": "your-secret-key-with-32-characters"
  }
}

Or with a ready-made AES key in Base64 (recommended β€” the key is used directly, without derivation):

{
  "Cryptography": {
    "Algorithm": "GCM",
    "SecretBase64": "32-byte-key-in-base64"
  }
}
JwtOptions properties
Property Type Default Description
Algorithm string ES256 Signing algorithm. Unknown values throw
Secret string? null Key for symmetric algorithms (HS256/384/512)
PrivateKey string? null Base64 private key (PKCS#8) for signing
PublicKey string? null Base64 public key (SPKI) for validation
Issuer string? null Issuer accepted on validation and written to the token
Issuers string[]? null Additional issuers accepted on validation
Audience string? null Audience accepted on validation and written to the token
Audiences string[]? null Additional audiences accepted on validation
ExpirationTime int 5 Token expiration in minutes

Issuer/Issuers and Audience/Audiences add up: providing any of them turns on the validation of that field. When none is provided, the validation of that field is turned off. The audience parameter of Create and Validate/ValidateAsync takes precedence over the configuration.

PrivateKey and PublicKey accept both the raw Base64 and the full PEM: the -----BEGIN/END ... KEY----- delimiters and the line breaks are removed on assignment.

Example with multiple issuers and audiences:

{
  "Jwt": {
    "Algorithm": "ES256",
    "PublicKey": "your-public-key-in-base64",
    "Issuers": ["legacy-api", "new-api"],
    "Audiences": ["web-app", "mobile-app"],
    "ExpirationTime": 60
  }
}
CryptographyOptions properties
Property Type Default Description
Algorithm string GCM AES-256 mode: GCM, CBC or CBCUnsafe (decrypt only)
Secret string? null Key derived via SHA256 (compatibility)
SecretBase64 string? null 32-byte AES key used directly (recommended)

Secret or SecretBase64 is required. When both are provided, SecretBase64 takes precedence. SecretBase64 must represent exactly 32 bytes (AES-256) β€” invalid values fail at startup. Generate a key with Convert.ToBase64String(RandomNumberGenerator.GetBytes(32)). With Secret, the key is derived via SHA256 (kept for compatibility).

Program.cs

using Tooark.Securities.Injections;

var builder = WebApplication.CreateBuilder(args);

// Adds the security services
builder.Services.AddTooarkSecurities(builder.Configuration);

var app = builder.Build();

Or, to add only the JWT token service:

using Tooark.Securities.Injections;

var builder = WebApplication.CreateBuilder(args);

// Adds the security services
builder.Services.AddTooarkJwtToken(builder.Configuration);

var app = builder.Build();

Or, to add only the cryptography service:

using Tooark.Securities.Injections;

var builder = WebApplication.CreateBuilder(args);

// Adds the security services
builder.Services.AddTooarkCryptography(builder.Configuration);

var app = builder.Build();

πŸ” JWT - Supported Algorithms

Symmetric Algorithms (HMAC)

Algorithm Description Requirements
HS256 HMAC-SHA256 Secret (β‰₯32 bytes)
HS384 HMAC-SHA384 Secret (β‰₯48 bytes)
HS512 HMAC-SHA512 Secret (β‰₯64 bytes)

The minimums follow RFC 7518 (HMAC key at least as long as the hash output) and are validated at startup (Options.Jwt.SecretTooShort). The size is measured in bytes (UTF-8): non-ASCII characters take more than one byte.

Asymmetric Algorithms (RSA)

Algorithm Description Requirements
RS256 RSA-SHA256 PrivateKey/PublicKey (β‰₯2048 bits)
RS384 RSA-SHA384 PrivateKey/PublicKey (β‰₯2048 bits)
RS512 RSA-SHA512 PrivateKey/PublicKey (β‰₯2048 bits)
PS256 RSA-PSS-SHA256 PrivateKey/PublicKey (β‰₯2048 bits)
PS384 RSA-PSS-SHA384 PrivateKey/PublicKey (β‰₯2048 bits)
PS512 RSA-PSS-SHA512 PrivateKey/PublicKey (β‰₯2048 bits)

Asymmetric Algorithms (ECDsa)

Algorithm Description Required Curve
ES256 ECDSA-SHA256 P-256 (secp256r1)
ES384 ECDSA-SHA384 P-384 (secp384r1)
ES512 ECDSA-SHA512 P-521 (secp521r1)

The default algorithm is ES256 when Algorithm is not provided. Unknown values throw (Options.Jwt.AlgorithmNotSupported) β€” in security configuration, an invalid algorithm is never silently replaced by another. Internally, creation and validation use the JsonWebTokenHandler (the current Microsoft.IdentityModel handler); UserTokenDto accepts both JsonWebToken and the legacy JwtSecurityToken.


πŸ”’ Cryptography - Supported Algorithms

Algorithm Mode Description
GCM AES-256-GCM Recommended - Authenticated encryption
CBC AES-256-CBC Traditional mode with random IV
CBCUnsafe AES-256-CBC ⚠️ Legacy - zero IV, decryption only

CBCUnsafe exists only to read old data encrypted with a zero IV: encrypting in this mode throws (Options.Cryptography.AlgorithmDecryptOnly). For new data, use GCM.


πŸ“ Usage Examples

JWT - Creating and Validating a Token

Configuration with HMAC (Symmetric)
{
  "Jwt": {
    "Algorithm": "HS256",
    "Secret": "my-super-secure-secret-key-32chars",
    "Issuer": "my-api",
    "Audience": "my-clients",
    "ExpirationTime": 60
  }
}
Configuration with RSA (Asymmetric)
{
  "Jwt": {
    "Algorithm": "RS256",
    "PrivateKey": "MIIEvQIBADANBgkqh...base64-private-key...",
    "PublicKey": "MIIBIjANBgkqhkiG9w...base64-public-key...",
    "Issuer": "my-api",
    "Audience": "my-clients",
    "ExpirationTime": 60
  }
}
Creating a Token
public class AuthController : ControllerBase
{
    private readonly IJwtTokenService _jwtService;

    public AuthController(IJwtTokenService jwtService)
    {
        _jwtService = jwtService;
    }

    [HttpPost("login")]
    public IActionResult Login(LoginRequest request)
    {
        // Validate credentials...

        // Create the token data
        var tokenData = new JwtTokenDto(
            id: user.Id,
            login: user.Email,
            security: user.SecurityStamp
        );

        // Generate the token
        var token = _jwtService.Create(tokenData);

        return Ok(new { Token = token });
    }

    // With a custom audience and extra claims
    [HttpPost("login-custom")]
    public IActionResult LoginCustom(LoginRequest request)
    {
        var tokenData = new JwtTokenDto(user.Id, user.Email, user.SecurityStamp);

        var extraClaims = new[]
        {
            new Claim("role", "admin"),
            new Claim("department", "IT")
        };

        var token = _jwtService.Create(tokenData, audience: "mobile-app", extraClaims: extraClaims);

        return Ok(new { Token = token });
    }
}
Validating a Token

The Microsoft.IdentityModel handler exposes validation only asynchronously, so ValidateAsync is the direct path and Validate is the synchronous wrapper. In code that is already asynchronous, prefer ValidateAsync:

[HttpGet("validate")]
public async Task<IActionResult> ValidateTokenAsync([FromHeader] string authorization)
{
    var token = authorization.Replace("Bearer ", "");

    var result = await _jwtService.ValidateAsync(token);

    if (!string.IsNullOrEmpty(result.ErrorToken))
    {
        return Unauthorized(new { Error = result.ErrorToken });
    }

    return Ok(new { UserId = result.Id, Login = result.Login });
}

In synchronous code, the blocking overload delivers the same result:

[HttpGet("validate")]
public IActionResult ValidateToken([FromHeader] string authorization)
{
    var token = authorization.Replace("Bearer ", "");

    var result = _jwtService.Validate(token);

    if (!string.IsNullOrEmpty(result.ErrorToken))
    {
        return Unauthorized(new { Error = result.ErrorToken });
    }

    return Ok(new
    {
        UserId = result.Id,
        Login = result.Login,
        // Or using the helpers
        GuidId = result.GetGuidId,
        IntId = result.GetIntId
    });
}

Cryptography - Encrypt and Decrypt

Configuration
{
  "Cryptography": {
    "Algorithm": "GCM",
    "Secret": "my-secret-key-32-characters-long"
  }
}
Using ICryptographyService
public class DataProtectionService
{
    private readonly ICryptographyService _crypto;

    public DataProtectionService(ICryptographyService crypto)
    {
        _crypto = crypto;
    }

    public string ProtectSensitiveData(string plainText)
    {
        // Returns the encrypted text in Base64
        return _crypto.Encrypt(plainText);
    }

    public string UnprotectData(string encryptedText)
    {
        // Returns the original decrypted text
        return _crypto.Decrypt(encryptedText);
    }
}
Full Example
// Configure in Program.cs (registers ICryptographyService as a singleton)
builder.Services.AddTooarkCryptography(builder.Configuration);

// Use in the service
public class UserService
{
    private readonly ICryptographyService _crypto;

    public UserService(ICryptographyService crypto)
    {
        _crypto = crypto;
    }

    public void SaveUser(User user)
    {
        // Encrypt sensitive data before saving
        user.CreditCard = _crypto.Encrypt(user.CreditCard);
        user.SSN = _crypto.Encrypt(user.SSN);

        // Save to the database...
    }

    public User GetUser(int id)
    {
        var user = // Fetch from the database...

        // Decrypt sensitive data
        user.CreditCard = _crypto.Decrypt(user.CreditCard);
        user.SSN = _crypto.Decrypt(user.SSN);

        return user;
    }
}

πŸ”‘ Generating Keys

Key for HMAC (HS256/HS384/HS512)

# Generate a random 32-byte (256-bit) key for HS256
openssl rand -base64 32

# Generate a random 64-byte (512-bit) key for HS512
openssl rand -base64 64

RSA Keys (RS256/PS256)

# Generate a 2048-bit RSA private key
openssl genrsa -out private.pem 2048

# Extract the public key
openssl rsa -in private.pem -pubout -out public.pem

# Convert to the PKCS8 format (recommended)
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.pem -out private_pkcs8.pem

# Get the key in Base64 (without headers)
cat private_pkcs8.pem | grep -v "BEGIN\|END" | tr -d '\n'
cat public.pem | grep -v "BEGIN\|END" | tr -d '\n'

ECDsa Keys (ES256/ES384/ES512)

# ES256 (P-256)
openssl ecparam -genkey -name prime256v1 -noout -out ec_private.pem
openssl ec -in ec_private.pem -pubout -out ec_public.pem

# ES384 (P-384)
openssl ecparam -genkey -name secp384r1 -noout -out ec_private.pem

# ES512 (P-521)
openssl ecparam -genkey -name secp521r1 -noout -out ec_private.pem

# Convert to PKCS8
openssl pkcs8 -topk8 -nocrypt -in ec_private.pem -out ec_private_pkcs8.pem

πŸ“‹ Dependencies

Package Version Description
Tooark.Exceptions 4.x Exceptions (e.g. BadRequestException)
Microsoft.AspNetCore.Authentication.JwtBearer 8.x/10.x JWT authentication for ASP.NET Core

🎯 Best Practices

JWT

  1. Use asymmetric algorithms (RS/PS/ES) in production - Allows validating tokens without exposing the signing key
  2. Configure ExpirationTime appropriately - Short-lived tokens are safer
  3. Use Issuer and Audience - Prevents tokens from being misused across applications
  4. Store keys in a Secret Manager - Never commit keys to source code

Cryptography

  1. Prefer GCM over CBC - GCM provides built-in authentication
  2. Never use CBCUnsafe for new data - Decrypt-only mode for compatibility with legacy systems
  3. Prefer SecretBase64 with a random 32-byte key - The key is used directly, without derivation
  4. Generate random keys - Use openssl rand -base64 32 or RandomNumberGenerator.GetBytes(32)

⚠️ Error Codes and Solutions

Service Message Description Solution Exception
CryptographyService Options.NotConfigured Options not configured Configure CryptographyOptions InternalServerError
CryptographyService Options.Cryptography.SecretNotConfigured No key configured Configure Secret or SecretBase64 in CryptographyOptions InternalServerError
CryptographyService Options.Cryptography.SecretBase64Invalid SecretBase64 is not valid Base64 Provide a valid Base64 value in SecretBase64 InternalServerError
CryptographyService Options.Cryptography.SecretBase64InvalidSize SecretBase64 is not 32 bytes Use a key of exactly 32 bytes (AES-256) InternalServerError
CryptographyService Options.Cryptography.AlgorithmDecryptOnly CBCUnsafe used to encrypt Use CBCUnsafe only to decrypt legacy data InternalServerError
CryptographyService Cryptography.PlainTextNotProvided PlainText not provided Provide the plain text to encrypt BadRequest
CryptographyService Cryptography.CipherTextNotProvided CipherText not provided Provide the encrypted text to decrypt BadRequest
CryptographyService Cryptography.InvalidCipherText Invalid CipherText Provide a valid encrypted text to decrypt BadRequest
JwtTokenService Options.NotConfigured Options not configured Configure JwtOptions InternalServerError
JwtTokenService Options.Jwt.SecretNotConfigured Secret not configured Configure Secret in JwtOptions for a symmetric token InternalServerError
JwtTokenService Options.Jwt.SecretTooShort Secret below the algorithm minimum Use at least 32/48/64 bytes for HS256/HS384/HS512 InternalServerError
JwtTokenService Options.Jwt.KeysNotConfigured Private and Public not configured Configure the keys in JwtOptions for an asymmetric token InternalServerError
JwtTokenService Options.Jwt.PrivateKey.InvalidSize Invalid Private key size Use a Private key of at least 2048 bits InternalServerError
JwtTokenService Options.Jwt.PublicKey.InvalidSize Invalid Public key size Use a Public key of at least 2048 bits InternalServerError
JwtTokenService Options.Jwt.PrivateKey.InvalidCurve Invalid Private key curve Use a Private key with the correct curve InternalServerError
JwtTokenService Options.Jwt.PublicKey.InvalidCurve Invalid Public key curve Use a Public key with the correct curve InternalServerError
JwtTokenService Options.Jwt.InvalidKey Invalid key Use valid keys for the chosen algorithm InternalServerError
JwtTokenService Options.Jwt.AlgorithmNotSupported Unsupported algorithm Use a supported algorithm InternalServerError
JwtTokenService Options.Jwt.KeyNotConfigured;PrivateKey Private key not configured Configure PrivateKey in JwtOptions to generate a token InternalServerError
JwtTokenService Options.Jwt.KeyNotConfigured;PublicKey Public key not configured Configure PublicKey in JwtOptions to validate a token InternalServerError
JwtTokenService Token.Expired Expired token Generate a new token N/A
JwtTokenService Token.InvalidSignature Token with an invalid signature Use only tokens with a valid signature N/A
JwtTokenService Token.Invalid Invalid token Use only valid tokens N/A
JwtTokenService InternalServerError Internal server error Check the logs for details N/A

πŸͺͺ Contributing

Contributions are welcome! Feel free to open issues and pull requests in the Tooark.Securities repository.

πŸ“„ License

This project is licensed under the BSD 3-Clause License. See the LICENSE file for details.

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

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Tooark.Securities:

Package Downloads
Tooark

Package with all Tooark resources for .NET applications.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.7.1 0 10/17/2026
4.7.0 273 9/30/2026
4.6.0 144 9/29/2026
4.5.0 113 9/29/2026
4.4.0 108 9/28/2026
4.3.0 118 9/26/2026
4.2.1 120 9/25/2026
4.2.0 118 9/20/2026
4.1.0 106 9/18/2026
4.0.1 123 8/25/2026
4.0.0 129 8/25/2026
3.3.6 110 9/18/2026
3.3.5 115 8/25/2026
3.3.4 127 8/12/2026
3.3.3 138 7/27/2026
3.3.2 313 6/11/2026
3.3.1 159 6/6/2026
2.3.5 102 9/18/2026
2.3.4 122 8/25/2026
2.3.3 126 7/27/2026
Loading failed