Files
2026-06-19 20:18:29 +02:00

272 lines
4.6 KiB
Markdown

# 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.0` compatibility
## 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:
```csharp
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:
```bash
dotnet add package EonaCat.SecureToken
```
# Quick Start
## Create a token service
```csharp
using EonaCat.SecureToken.Core;
using EonaCat.SecureToken.Cryptography;
var keys = SigningKeyStore.CreateNew();
var tokens = new TokenService(keys);
```
## Issue an access token
```csharp
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
```csharp
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
```csharp
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:
```csharp
var pair = tokens.IssueTokenPair(
"user-1",
"api",
"mobile"
);
Console.WriteLine(pair.AccessToken);
Console.WriteLine(pair.RefreshToken);
```
Validate separately:
```csharp
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:
```csharp
var token = tokens.Issue(
TokenDescriptor.Create()
.ForSubject("user-1")
.IssuedBy("api")
.ForAudience("web")
.BoundTo("device-identifier")
);
```
Validation:
```csharp
new TokenValidationOptions
{
ValidIssuer = "api",
ValidAudience = "web",
BindingContext = "device-identifier"
};
```
# Revocation
You can integrate your own revocation storage:
```csharp
var options = new TokenValidationOptions
{
ValidIssuer = "api",
ValidAudience = "web",
RevocationCheck = async (tokenId, cancellationToken) =>
{
return await database.IsRevoked(tokenId);
}
};
```
# ASP.NET Core dependency injection
```csharp
builder.Services.AddSecureTokens();
```
or provide your own key store:
```csharp
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 Framework 4.8
- .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.