Skip to content

scottbrady91/IdentityModel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

dc78d19 · Nov 20, 2024
Nov 20, 2024
Nov 20, 2024
Nov 20, 2024
Nov 20, 2024
Apr 28, 2020
Apr 27, 2020
Mar 29, 2024
Jul 5, 2022
Mar 29, 2024
Jul 14, 2022

Repository files navigation

ScottBrady.IdentityModel

NuGet

Helper libraries for tokens and cryptography in .NET.

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

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

EdDSA support

EdDSA is a modern signing algorithm that is 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))

Base16 (hex) Encoding

Base16 allows you to encode and decode hexadecimal 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));

JWT alternatives (deprecated)

Branca Tokens

Branca is a 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);

Important

Branca support is now deprecated and only supports Microsoft.IdentityModel 6.35.0. This is due to the low usage of this library and the Branca project as a whole.

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);

Important

PASETO support is now deprecated and only supports Microsoft.IdentityModel 6.35.0. This is due to the low usage of this library and the PASETO project as a whole.

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";
    })