Files
EonaCat.SecureToken/README.md
T

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.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:

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.