Tooark.Securities
4.2.1
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
<PackageReference Include="Tooark.Securities" Version="4.2.1" />
<PackageVersion Include="Tooark.Securities" Version="4.2.1" />
<PackageReference Include="Tooark.Securities" />
paket add Tooark.Securities --version 4.2.1
#r "nuget: Tooark.Securities, 4.2.1"
#:package Tooark.Securities@4.2.1
#addin nuget:?package=Tooark.Securities&version=4.2.1
#tool nuget:?package=Tooark.Securities&version=4.2.1
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/IssuersandAudience/Audiencesadd up: providing any of them turns on the validation of that field. When none is provided, the validation of that field is turned off. Theaudienceparameter ofCreateandValidate/ValidateAsynctakes precedence over the configuration.
PrivateKeyandPublicKeyaccept 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) |
SecretorSecretBase64is required. When both are provided,SecretBase64takes precedence.SecretBase64must represent exactly 32 bytes (AES-256) β invalid values fail at startup. Generate a key withConvert.ToBase64String(RandomNumberGenerator.GetBytes(32)). WithSecret, 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
ES256whenAlgorithmis 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 theJsonWebTokenHandler(the current Microsoft.IdentityModel handler);UserTokenDtoaccepts bothJsonWebTokenand the legacyJwtSecurityToken.
π 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 |
CBCUnsafeexists only to read old data encrypted with a zero IV: encrypting in this mode throws (Options.Cryptography.AlgorithmDecryptOnly). For new data, useGCM.
π 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
- Use asymmetric algorithms (RS/PS/ES) in production - Allows validating tokens without exposing the signing key
- Configure
ExpirationTimeappropriately - Short-lived tokens are safer - Use
IssuerandAudience- Prevents tokens from being misused across applications - Store keys in a Secret Manager - Never commit keys to source code
Cryptography
- Prefer GCM over CBC - GCM provides built-in authentication
- Never use CBCUnsafe for new data - Decrypt-only mode for compatibility with legacy systems
- Prefer
SecretBase64with a random 32-byte key - The key is used directly, without derivation - Generate random keys - Use
openssl rand -base64 32orRandomNumberGenerator.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 | 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 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. |
-
net10.0
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 10.0.12)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.12)
- Tooark.Exceptions (>= 4.2.1)
-
net8.0
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 8.0.31)
- Tooark.Exceptions (>= 4.2.1)
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 |