4.5 KiB
EonaCat.SecureToken
Secure, modern token library for .NET with key rotation, signing isolation, validation rules, and .NET Standard support.
EonaCat.SecureToken provides a safer alternative to rolling your own authentication tokens. It focuses on:
- Strong cryptographic signing
- Versioned key management
- Token lifecycle validation
- Refresh/access token separation
- Extensible claims
- API-friendly validation results
.NET Standard 2.0compatibility
Features
Cryptographic protection
- HMAC based token signing
- HKDF derived context-specific keys
- Constant-time signature verification
- Tamper detection
- Strong random key generation
Key rotation
Rotate signing keys without invalidating existing tokens.
Example:
var store = SigningKeyStore.CreateNew();
var service = new TokenService(store);
var oldToken = service.Issue(
TokenDescriptor.Create()
.ForSubject("user-123")
.IssuedBy("my-api")
.ForAudience("mobile")
);
// Rotate keys
store.Rotate();
// New tokens use the new key
var newToken = service.Issue(
TokenDescriptor.Create()
.ForSubject("user-456")
.IssuedBy("my-api")
.ForAudience("mobile")
);
// Old token still validates
service.Validate(
oldToken,
TokenValidationOptions.AccessToken("my-api", "mobile")
);
Installation
Install from NuGet:
dotnet add package EonaCat.SecureToken
Quick Start
Create a token service
using EonaCat.SecureToken.Core;
using EonaCat.SecureToken.Cryptography;
var keys = SigningKeyStore.CreateNew();
var tokens = new TokenService(keys);
Issue an access token
var token = tokens.Issue(
TokenDescriptor.Create()
.ForSubject("user-123")
.IssuedBy("my-service")
.ForAudience("api")
.WithRole("admin")
.WithClaim("email", "user@example.com")
);
The token contains:
- Subject
- Issuer
- Audience
- Roles
- Custom claims
- Token ID
- Expiration
- Key generation information
Validate a token
var result = tokens.Validate(
token,
TokenValidationOptions.AccessToken(
issuer: "my-service",
audience: "api"
)
);
if (result.IsSuccess)
{
var claims = result.UnwrapClaims();
Console.WriteLine(claims.Subject);
}
Token expiration
var token = tokens.Issue(
TokenDescriptor.Create()
.ForSubject("user-1")
.IssuedBy("api")
.ForAudience("mobile")
.WithLifetime(TimeSpan.FromMinutes(15))
);
Expired tokens are automatically rejected.
Refresh tokens
Create a refresh token:
var pair = tokens.IssueTokenPair(
"user-1",
"api",
"mobile"
);
Console.WriteLine(pair.AccessToken);
Console.WriteLine(pair.RefreshToken);
Validate separately:
tokens.Validate(
pair.RefreshToken,
TokenValidationOptions.RefreshToken("api")
);
Refresh tokens cannot be used as access tokens.
Token binding
Bind tokens to a context such as a device or session:
var token = tokens.Issue(
TokenDescriptor.Create()
.ForSubject("user-1")
.IssuedBy("api")
.ForAudience("web")
.BoundTo("device-identifier")
);
Validation:
new TokenValidationOptions
{
ValidIssuer = "api",
ValidAudience = "web",
BindingContext = "device-identifier"
};
Revocation
You can integrate your own revocation storage:
var options = new TokenValidationOptions
{
ValidIssuer = "api",
ValidAudience = "web",
RevocationCheck = async (tokenId, cancellationToken) =>
{
return await database.IsRevoked(tokenId);
}
};
ASP.NET Core dependency injection
builder.Services.AddSecureTokens();
or provide your own key store:
builder.Services.AddSecureTokens(
store =>
{
return SigningKeyStore.FromKeys(
new[]
{
(1, secretKeyBytes)
});
});
Security design
The library separates cryptographic purposes:
Master Key
|
+-- Signing Key
|
+-- Encryption Key
|
+-- Context-specific keys
This prevents accidental key reuse between operations.
Supported frameworks
- .NET Standard 2.0
- .NET Standard 2.1
- .NET 8+
When to use
Good fit for:
APIs
Microservices
Internal authentication
Service-to-service tokens
Applications needing key rotation
When not to use
Do not store secrets directly in source code.
Use:
- Environment variables
- Secret managers
- Hardware-backed key storage where required
License
Apache License.