/Credible

Json Web Token authentication library for .NET Core.

Primary LanguageC#MIT LicenseMIT

Credible

Simple Json Web Token library for .NET

Installation

Package Manager

Install-Package Credible

.NET CLI

dotnet add package Credible

Getting Started

  1. Create an identity model to be used in your application.
public class UserIdentity
{
    public int UserId { get; set; }
    public string Username { get; set; }
    public IEnumerable<string> Permissions { get; set; }
}
  1. Create a payload factory to convert your identity model into a token.
public class PayloadFactory : IPayloadFactory<UserIdentity>
{
    public IDictionary<string, object> Create(UserIdentity identity)
    {
        return new Dictionary<string, object>
        {
            { "userId", identity.UserId },
            { "username", identity.Username },
            { "permissions", identity.Permissions }
        };
    }
}
  1. Create a user factory to convert your token back into an identity.
public class UserIdentityFactory : IIdentityFactory<UserIdentity>
{
    public UserIdentity Create(ClaimsPrincipal principal)
    {
        return new UserIdentity
        {
            UserId = int.Parse(principal.FindFirst("userId")?.Value ?? "0"),
            Username = principal.FindFirst("username")?.Value ?? "",
            Permissions = principal.FindAll("permissions").Select(e => e.Value)
        };
    }
}
  1. Configure authentication in Startup.cs. Make sure you add app.UseAuthentication() above app.UseMvc() in Configure.
public class Startup
{
    //...
    public void ConfigureServices(IServiceCollection services)
    {
        //...
        var securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("My super secret key."));

        services.AddCredible<UserIdentity, UserIdentityFactory, PayloadFactory>(
            issuingOptions =>
            {
                issuingOptions.Audience = "WebApiSample";
                issuingOptions.Issuer = "WebApiSample";
                issuingOptions.Expiration = TimeSpan.FromMinutes(30);
                issuingOptions.SigningCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
            },
            validationOptions =>
            {
                validationOptions.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = securityKey,
                    ValidIssuer = "WebApiSample",
                    ValidAudience = "WebApiSample",
                    NameClaimType = "username"
                };
                validationOptions.Audience = "WebApiSample";
                validationOptions.ClaimsIssuer = "WebApiSample";
                validationOptions.Challenge = "Bearer";
            }
        );
        //...
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        //...
        app.UseAuthentication();
        app.UseMvc();
        //...
    }
}
  1. Inject your JsonWebTokenFactory<TIdentity> into your controller and call the create method to create a new token based on the identity model.
[Route("api/token")]
[ApiController]
public class TokenController : ControllerBase
{
    private readonly JsonWebTokenFactory<UserIdentity> _tokenFactory;

    public TokenController(JsonWebTokenFactory<UserIdentity> tokenFactory)
    {
        _tokenFactory = tokenFactory ?? throw new ArgumentNullException(nameof(tokenFactory));
    }

    // GET api/token
    [HttpPost("")]
    public ActionResult<JsonWebToken> Get(UserIdentity identity)
    {
        return _tokenFactory.Create(identity);
    }
}
  1. Inject your identity class into a controller to use it to get the current user.
[Route("api/user")]
[ApiController]
[Authorize]
public class UserController : ControllerBase
{
    private readonly UserIdentity _user;

    public UserController(UserIdentity user)
    {
        _user = user;
    }

    // GET api/user
    [HttpGet("")]
    public ActionResult<UserIdentity> Get()
    {
        return _user;
    }
}

Separate Issuing and Validation

If you want to separate issue and validation, you can configure them separately.

Validation Only

Validation requires the authentication middleware, so be sure to add app.UseAuthentication(); like the example above.

services.AddCredible<UserIdentity, UserIdentityFactory>(
    validationOptions =>
    {
        validationOptions.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = securityKey,
            ValidIssuer = "WebApiSample",
            ValidAudience = "WebApiSample",
            NameClaimType = "username"
        };
        validationOptions.Audience = "WebApiSample";
        validationOptions.ClaimsIssuer = "WebApiSample";
        validationOptions.Challenge = "Bearer";
    }
);

Issuing Only

Issuing doesn't require the authentication middleware or the AuthenticationBuilder to be used. Just call AddCredible on the IServiceCollection directly.

services.AddCredible<UserIdentity, PayloadFactory>(
    issuingOptions =>
    {
        issuingOptions.Audience = "WebApiSample";
        issuingOptions.Issuer = "WebApiSample";
        issuingOptions.Expiration = TimeSpan.FromMinutes(30);
        issuingOptions.SigningCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
    }
);