EduardoPires / Jwks.Manager

Json Web Key Set Manager. This component automate OAuth 2.0 rotating keys, jwks_uri. Keeping you JWK in a single place, secure and give hability to support Load Balance Scenarios.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Json Web Key Set Manager

NugetAzure DevOps coverageBuild Status

The JSON Web Key Set (JWKS) is a set of keys which contains the public keys used to verify any JSON Web Token (JWT) issued by the authorization server. The main goal of this component is to provide a centralized store and Key Rotation of your JWK. It also provide features to generate best practices JWK. It has a plugin for IdentityServer4, giving hability to rotating jwks_uri every 90 days and auto manage your jwks_uri.

If your API or OAuth 2.0 is under Load Balance in Kubernetes, or docker swarm it's a must have component. It work in the same way DataProtection Key of ASP.NET Core.

Table of Contents


How

First choose where to store your JWK's.

Database

The Jwks.Manager.Store.EntityFrameworkCore package provides a mechanism for storing JsonWebKeys to a database using Entity Framework Core. The Jwks.Manager.Store.EntityFrameworkCore NuGet package must be added to the project file.

With this package, keys can be shared across multiple instances of a web app.

First install

    Install-Package Jwks.Manager.Store.EntityFrameworkCore

Or via the .NET Core command line interface:

    dotnet add package Jwks.Manager.Store.EntityFrameworkCore

Change your Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));

    // Add a DbContext to store your Database Keys
    services.AddDbContext<MyKeysContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("MyKeysConnection")));

    // using Jwks.Manager.Store.EntityFrameworkCore;
    services.AddJwksManager().PersistKeysToDatabaseStore<MyKeysContext>();

}

The generic parameter, TContext, must inherit from DbContext and implement ISecurityKeyContext:

using Jwks.Manager.Store.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using WebApp1.Data;

namespace WebApp1
{
    class MyKeysContext : DbContext, ISecurityKeyContext
    {
        // A recommended constructor overload when using EF Core 
        // with dependency injection.
        public MyKeysContext(DbContextOptions<MyKeysContext> options) 
            : base(options) { }

        // This maps to the table that stores keys.
        public DbSet<SecurityKeyWithPrivate> DataProtectionKeys { get; set; }
    }
}

Done!

File system

To configure a file system-based key repository, call the PersistKeysToFileSystem configuration routine as shown below. Provide a DirectoryInfo pointing to the repository where keys should be stored:

public void ConfigureServices(IServiceCollection services)
{
    services.AddJwksManager().PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys\"));
}

Changing Algorithm

It's possible to change default Algorithm at configuration routine.

public void ConfigureServices(IServiceCollection services)
{
    services.AddJwksManager(o => o.Algorithm = Algorithm.RS384).PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys\"));
}

The Algorithm object has a list of possibilities:

Shortname Name
HS256 Hmac Sha256
HS384 Hmac Sha384
HS512 Hmac Sha512
RS256 Rsa Sha256
RS384 Rsa Sha384
RS512 Rsa Sha512
PS256 Rsa SsaPss Sha256
PS384 Rsa SsaPss Sha384
PS512 Rsa SsaPss Sha512
ES256 Ecdsa Sha256
ES384 Ecdsa Sha384
ES512 Ecdsa Sha512

IdentityServer4 - Auto jwks_uri Management

If you have an IdentityServer4 OAuth 2.0 Server, you can use this component plugin.

First install

    Install-Package Jwks.Manager.IdentityServer4

Or via the .NET Core command line interface:

    dotnet add package Jwks.Manager.IdentityServer4

Go to Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        var builder = services.AddIdentityServer()
            .AddInMemoryIdentityResources(Config.GetIdentityResources())
            .AddInMemoryApiResources(Config.GetApis())
            .AddInMemoryClients(Config.GetClients());

        services.AddJwksManager().IdentityServer4AutoJwksManager().PersistKeysToFileSystem(new DirectoryInfo(_env.WebRootPath));
    }

If you wanna use Database, follow instructions to DatabaseStore instead.

Signing JWT

To signing a JWT Token do as follow.

First inject:

    public class AccessManager
    {
        private readonly IJsonWebKeySetService _jwksService;

        public AccessManager(IJsonWebKeySetService jwksService)
        {
            _jwksService = jwksService;
        }
    }

Then, after a successfull login, create a routine to generate token.

    public Token GenerateToken(User user)
    {
        ClaimsIdentity identity = new ClaimsIdentity(
            new GenericIdentity(user.UserID, "Login"),
            new[] {
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")),
                new Claim(JwtRegisteredClaimNames.UniqueName, user.UserID)
            }
        );

        var now = DateTime.Now;

        var handler = new JsonWebTokenHandler();
        var descriptor = new SecurityTokenDescriptor
        {
            Issuer = "me",
            Audience = "you",
            SigningCredentials = _jwksService.GetCurrent(),
            Subject = identity,
            NotBefore = now,
            Expires = now.AddHours(1)
        };

        var jwt = handler.CreateToken(descriptor);

        return new Token()
        {
            Authenticated = true,
            Created = now.ToString("yyyy-MM-dd HH:mm:ss"),
            Expiration = now.AddHours(1).ToString("yyyy-MM-dd HH:mm:ss"),
            AccessToken = jwt,
            Message = "OK"
        };
    }

Token Validation

To validate a token it's as simple as that:

    var result = handler.ValidateToken(jwt,
            new TokenValidationParameters
            {
                ValidIssuer = "me",
                ValidAudience = "you",
                IssuerSigningKey = _jwksService.GetCurrent(options).Key
            });

Why

When creating applications and APIs in OAuth 2.0 or simpling Signing a JWT Key, many algorithms are supported. While there a subset of alg's, some of them are considered best practices, and better than others. Like Elliptic Curve with PS256 algorithm. Some Auth Servers works with Deterministic and other with Probabilist. Some servers like Auth0 doesn't support more than one JWK. But IdentityServer4 support as many as you configure. So this component came to abstract this layer and offer for your application the current best practies for JWK.

Load Balance scenarios

When working in containers with Kubernetes or Docker Swarm, if your application scale them you became to have some problems, like DataProtection Keys that must be stored in a centralized place. While isn't recommended to avoid this situation Symmetric Key is a way. So this component, like DataProtection, provide a Centralized store for your JWKS.

Best practices

Many developers has no clue about which Algorithm to use for sign their JWT. This component uses Elliptic Curve with ECDSA using P-256 and SHA-256 as default. It should help to build more secure API's and environments providing JWKS management.


License

Jwks.Manager is Open Source software and is released under the MIT license. This license allow the use of Jwks.Manager in free and commercial applications and libraries without restrictions.

About

Json Web Key Set Manager. This component automate OAuth 2.0 rotating keys, jwks_uri. Keeping you JWK in a single place, secure and give hability to support Load Balance Scenarios.

License:MIT License


Languages

Language:Smalltalk 83.8%Language:C# 15.7%Language:PowerShell 0.5%