IdentityModel icon indicating copy to clipboard operation
IdentityModel copied to clipboard

JWT style token handlers for Branca and PASETO in .NET. EdDSA support for Microsoft.IdentityModel.

ScottBrady.IdentityModel

NuGet

Helper libraries for tokens and cryptography in .NET.

  • EdDSA support for JWTs (Ed25519 and Ed448)
  • Branca tokens with JWT style validation
  • PASETO (v1.public & v2.public) with JWT style validation
  • Base16 (hex) and Base62 encoders
  • passwordrule attribute support for ASP.NET Identity
  • Samples in ASP.NET Core

Feature requests welcome. Please see SECURITY.md for responsible disclosure policy.

EdDSA support

EdDSA is a modern signing algorithm, not yet supported out of the box in .NET. This library provides some useful abstractions around the Bouncy Castle (software) implementation of EdDSA.

// create EdDSA new key pair
EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519)

// create EdDSA key from parameters
EdDsa.Create(new EdDsaParameters(ExtendedSecurityAlgorithms.Curves.Ed25519) 
  {D = Base64UrlEncoder.DecodeBytes(privateKey)})

// create EdDSA security key for use with Microsoft.IdentityModel JWT APIs (alg: EdDSA)
new EdDsaSecurityKey(EdDsa.Create(ExtendedSecurityAlgorithms.Curves.Ed25519))

Branca Tokens

Branca is token construct suitable for internal systems. The payload is encrypted using XChaCha20-Poly1305, using a 32-byte symmetric key.

This library supports the creation of Branca tokens with an arbitrary payload or using a JWT-style payload.

var handler = new BrancaTokenHandler();
var key = Encoding.UTF8.GetBytes("supersecretkeyyoushouldnotcommit");

// JWT-style payload
string token = handler.CreateToken(new SecurityTokenDescriptor
{
    Issuer = "me",
    Audience = "you",
    Expires = DateTime.UtcNow.AddMinutes(5),
    NotBefore = DateTime.UtcNow,
    Claims = new Dictionary<string, object> {{"sub", "123"}},
    EncryptingCredentials = new EncryptingCredentials(
        new SymmetricSecurityKey(key), ExtendedSecurityAlgorithms.XChaCha20Poly1305)
});

ClaimsPrincipal principal = handler.ValidateToken(
    token,
    new TokenValidationParameters
    {
        ValidIssuer = "me",
        ValidAudience = "you",
        TokenDecryptionKey = new SymmetricSecurityKey(key)
    }, out SecurityToken parsedToken);

PASETO

PASETO is a competing standard to JOSE & JWT that offers a versioned ciphersuite. This library currently implements v1 and v2 for the public purpose, suitable for zero-trust systems such as an OAuth authorization server.

Explicit versioning allows PASETO to side-step attacks on signature validation found in some JWT libraries. However, it does not mitigate any other attacks.

If you are considering using PASETO, I recommend reading RFC 8725 - JWT Best Current Practices and deciding if the interoperable JWT format is still wrong for you.

var handler = new PasetoTokenHandler();
var privateKey = Convert.FromBase64String("TYXei5+8Qd2ZqKIlEuJJ3S50WYuocFTrqK+3/gHVH9B2hpLtAgscF2c9QuWCzV9fQxal3XBqTXivXJPpp79vgw==");
var publicKey = Convert.FromBase64String("doaS7QILHBdnPULlgs1fX0MWpd1wak14r1yT6ae/b4M=");

string token = handler.CreateToken(new PasetoSecurityTokenDescriptor(
    PasetoConstants.Versions.V2, PasetoConstants.Purposes.Public)
{
    Issuer = "me",
    Audience = "you",
    Expires = DateTime.UtcNow.AddMinutes(5),
    NotBefore = DateTime.UtcNow,
    Claims = new Dictionary<string, object> {{"sub", "123"}},
    SigningCredentials = new SigningCredentials(
        new EdDsaSecurityKey(EdDsa.Create(
            new EdDsaParameters(ExtendedSecurityAlgorithms.Curves.Ed25519)
            {
                D = privateKey
            })), ExtendedSecurityAlgorithms.EdDsa)
});

ClaimsPrincipal principal = handler.ValidateToken(
    token,
    new TokenValidationParameters
    {
        ValidIssuer = "me",
        ValidAudience = "you",
        IssuerSigningKey = new EdDsaSecurityKey(EdDsa.Create(
            new EdDsaParameters(ExtendedSecurityAlgorithms.Curves.Ed25519) {X = publicKey}))
    }, out SecurityToken parsedToken);

API Protection with JWT Style Handler

The Branca and PASETO token handlers can be used with the ASP.NET Core JWT bearer authentication handler.

services.AddAuthentication()
    .AddJwtBearer("paseto", options =>
    {
        options.SecurityTokenValidators.Clear();
        options.SecurityTokenValidators.Add(new PasetoTokenHandler());
        options.TokenValidationParameters.IssuerSigningKey = new EdDsaSecurityKey(EdDSA.Create(<your_public_key>));
        options.TokenValidationParameters.ValidIssuer = "you";
        options.TokenValidationParameters.ValidAudience = "me";
    })

Base16 (hex) Encoding

Base16 allows you to encode and decode hexidecimal strings..

var plaintext = "hello world"; // encoded = 68656c6c6f20776f726c64
string encoded = Base16.Encode(Encoding.UTF8.GetBytes(plaintext));

Base62 Encoding

Base62 encoding uses the 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz character set.

var plaintext = "hello world"; // encoded = AAwf93rvy4aWQVw
string encoded = Base62.Encode(Encoding.UTF8.GetBytes(plaintext));