Issuing and authenticating JWT tokens in ASP.NET Core WebAPI – Part I


Big, important announcement regarding ASP.NET Core 2.0 – This tutorial covers requirements for ASP.NET Core 1.x. The principles remain the same, but the implementation is definitely different. If you are interested in seeing what changed between the setup for Core 1.x and Core 2.0, please look at this PR by Nico Jansen on the demo repo.

Introduction

If you’d like to see an example of how you can issue JWT tokens with ASP.NET Core 1 and automatically control access to bearers through the simple application of an [Authorize] attribute (specifically focusing on claims-based authorisation using ASP.NET Core MVC’s policy features) in a Web API project, then you are in the right place!

This post is the first part of this epic endeavour and will address the “Issuing” aspects of the problem, which entails:

  1.  Initial Setup – this will focus on the “scaffolding” that will be used both by the ‘token server’ side as well as the ‘resource server’ side of the example solution
  2. Issuing a JSON Web Token – which focuses on just that as well as how you can validate that it all works.
    1. Options and Configuration
    2. Adding the Controller
    3. Testing the JWT Controller
  3. What to expect in Part II
  4. Links

If you’re here because you require something that goes the distance with refresh tokens and proper identity management built in, I suggest you have a look at this tutorial by Sean Walsh on how to set up OpenIddict in ASP.NET Core.

Requirements

  1. An installation of the ASP.NET Core RTM (v 1.0.0) for your platform (I am on Windows 10 and using Visual Studio 2015 with Update 3 and ASP.NET Core Tools Preview 2.  Having said that, I’ve tested and confirmed that all the code and dependencies listed here also compiles and runs on Ubuntu 16.04).
  2. The source code for this demo so that you may see where the individual pieces I refer to in the gists below fit into the whole.

Assumed

  1. That you know what JSON Web Tokens are
  2. That you know how to create a Web API project with ASP.NET Core MVC
  3. That you know where the ASP.NET documentation is for anything not specifically mentioned that might be new to you (also feel free to ask in the comments)

Initial Setup

The example solution has the token server as well as the resource server in the same solution.  Since we require authentication on the resource side, best practice is to lock down everything and only open up the controllers and methods that you require.  In other words, instead of allowing anonymous access by default and closing down the controllers that require authentication, we require authentication by default and open up the controllers that are allowed to be accessed anonymously.  We do this by replacing the MVC service configuration in the ConfigureServices method in Startup.cs with the following:

Next we add a basic ApplicationUser model:

We will also require some way to configure our tokens and the way we do this is through the JwtIssuerOptions class that will allow us to set some of the JWT registered claim values as well as provide some additional functionality we require when signing the tokens we generate

Issuing a JSON Web Token

Options and Configuration

Before we create the JwtController, we need to configure the JwtIssuerOptions and set it up for injection.

The first thing we do is to add some configuration settings to appsettings.json, this file should have been created for us by VS as part of the scaffolding and we add a simple JwtIssuerOptions configuration section to it (lines 2 – 5)

NB! Take care that the ‘Audience’ value matches the ‘applicationUrl’ under ‘iisSettings’ -> ‘iisExpress’ in your ‘launchSettings.json’ file (under ‘Properties’ when you view your project in the VS Solution Explorer pane).

The next thing we do is to tell the app that we want to make use of options.  This is a single call to AddOptions on the services instance in the ConfigureServices method in Startup.cs (line 8) and the last part of the JwtIssuerOptions setup is to initialise an instance and make it available to the ASP.NET dependency injection system (lines 13 – 21 below).

Pay particular attention to the first two lines.  It is very, very important that you retrieve the SecretKey from some secure location such as Environment Settings and NOT like I did it here! The only reason I did it this way is to make the example easier to write and follow.

Note: you will notice that I use the nameof() expression extensively in the above setup.  I heartily recommend it!

Adding the Controller

Which finally brings us to the JwtController that will serve up the JSON Web Tokens for us

  • Line 16: sets up the route to match the controller name
  • Lines 23 – 24: sets up the controller via a basic constructor, notice how the JwtIssuerOptions are injected via the IOptions<TOptions> interface (I refer you again to the options and configuration documentation)
  • Lines 36 – 95: this is where our JWT is generated. Ideally we should have refactored this code for greater modularity, but I find examples easier to follow when everything is kept together so the purists among you must please bear with me.
    • Line 37: remember how we locked down access to only authenticated users in the very beginning? In order for this controller method to be accessible from the outside, we now have to explicitly allow for anonymous access.
    • Line 38: model binding in ASP.NET Core requires that we explicitly bind to the part of the POST that we are interested in, since we are POST-ing a ‘x-www-form-urlencoded’ form, we bind to the form.
    • Lines 40, 106 – 127: once again for the sake of example simplicity, I hard code information you’d normally retrieve from your data store in plain sight.  Two basic identities are possible in this example with the primary difference being that one has the ‘DisneyCharacter’ claim whereas the other does not.
    • Lines 47 – 55: add the claims
    • Lines 56 – 74: create the JwtSecurityToken, encode it and send it back to the caller as JSON (for interest’s sake, the JwtSecurityToken lives in System.IdentityModel.Tokens.Jwt, which comes with the NETStandard libraries, i.e. no additional package needs to be installed in order to use it)

Testing the JWT Controller

For the testing and validation part, you’ll need to have some way to send requests to the application.  I am particular to Postman and will be using it throughout.

  1. Fire up the example solution/your application
  2. If you are using the example solution, the application’s URL is http://localhost:1783/ (configured in launchSettings.json)
  3. Start up Postman

Configure a POST to http://localhost:1783/api/jwt with ‘x-www-form-urlencoded’ selected under Body. Provide two key/values for the form, ‘username’ as ‘MickeyMouse’ and ‘password’ as ‘MickeyMouseIsBoss123’ (remember these values are hard coded in the GetClaimsIdentity method on the JwtController)

MickeyMousePOST

Click ‘Send’ and wait (if you are running your solution through VS in Debug mode, you can put some breakpoints into the code to trace the process flow).  If everything was set up correctly, you should receive some JSON in the response body that looks similar to the below:

MickeyMousePOSTResponse

And that’s it, a basic, but functional, JSON Web Token Server.  Exciting times!

(if, for whatever reason, you failed and can’t figure out what is going on, feel free to ask in the comments)

Cheers!

(If you got this far and liked what you read, consider following me @thewillhallatt if you would like to be notified of future articles)

What to Expect in Part II

Part II addresses automatically controlling access to JWT bearers through the [Authorize] attribute (utilising JwtBearer authentication middleware), specifically focusing on user claims using ASP.NET Core MVC’s policy features in a Web API project.

  1. Token Authentication in ASP.NET Core (without this blog post by Nate Barbettini, this multi-part tutorial of mine would not have been possible)
  2. Supported Token and Claim Types (although aimed at Azure and ADAuth specifically, the first part is a useful, general overview of tokens
  3. ASP.NET Core Authorization Lab
Advertisements

57 Replies to “Issuing and authenticating JWT tokens in ASP.NET Core WebAPI – Part I”

    1. I think your problem is that you’re entering the username and password as post parameters rather than in the body. The Get() method signature requires them in the body. So for example if you’re using Postman, don’t enter the parameters in in the key/value pair section just below the URL, enter them under the body section after selecting x-www-form-urlencoded.

      You can change the method signature to accept parameters or other options as you see fit, but that’s how the example is given.

  1. Instead of using -www-form-urlencoded, I want to use application/json. the value of username and password becomes null. I found on the net that .net core by default accepts json. Why is it not working in my case?

  2. Excellent post, thank you, really appreciated your work on this.
    FYI: The JwtController’s action is marked as ‘HttpPost’´ but named ‘Get’.

  3. Maybe I messed something up, but when I set it up in my project following this tutorial (with ASP.NET Core 1.0.1), it seems like the controller’s JwtIssuerOptions instance isn’t being recreated for each call, so it retains the same IssuedAt and Expiration dates. This means that after a while it will start issuing already-expired tokens.

    1. Hi there!

      That is very likely, I never went further than testing the concepts, so please don’t use any of the code in the sample for production! I created this tutorial as part of the process I had to go through to understand how this all fits together, but I honestly cannot envision a scenario where I would actually “roll-my-own” (the risks are just too great). There are a number of very good, production-ready libraries out there that I would rather use (e.g. IdentityServer).

      Cheers,
      William.

    2. I just discovered the same issue.
      Fixed it by changing the properties in the options class like this: IssuedAt => DateTime.UtcNow, do this for all properties that must be dynamic.

  4. Great post! Can you please explain what changes we need to make to send JWTs as cookies instead of authorization bearer ?

  5. Very helpful, thanks!

    I have a question though:
    Are there any issues with using a randomly generated string as the key for symmetric encryption? I was thinking since the jwt’s are short lived, making them invalid at server restart won’t be an issue? Are there any security issues of using a randomly generated string as encryption key instead of grabbing it from an environment variable?

    1. Hi Fredrik, I don’t know if I am qualified to give a trustworthy answer to that question and I have never previously considered doing that. Having said that, as I am sitting here, I cannot immediately think of a downside to having a key that re-generates itself each time the server gets bounced. Your biggest “risk” would be in invalidating user’s access, but the worst that would happen in that case would be that the user will be required to log in again…I guess there is also a small risk of transactions failing due to some unforeseen circumstances. Anyhow, don’t take my word for it, we might both be wrong! 😀

  6. Hi, I have just used your work as a template in my project, it is working well but after the token expires and I sent a request for a new token and used the new token for the succeeding request, it always return error 401 and upon inspecting the result it have a message of token already expired, can you point me where to look at? Thanks

    1. Hi Caesar, I am sorry but I have absolutely no idea. Please do NOT use my code for anything resembling production, it is not safe enough, rather look at something like IdentityServer4. Cheers!

  7. Hi William Hallatt!
    It’s very simple to understand!
    But when I use https://jwt.io/ to check my token (eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNaWNrZXlNb3VzZSIsImp0aSI6IjlkODBiYjMwLTZiMTktNDQ1OS05ZGQxLWZlOTQ0YjhkMzBkNCIsImlhdCI6MTQ4NTIzMTg2MiwiRGlzbmV5Q2hhcmFjdGVyIjoiSUFtTWlja2V5IiwibmJmIjoxNDg1MjMxODYxLCJleHAiOjE0ODUyMzIxNjEsImlzcyI6IlN1cGVyQXdlc29tZVRva2VuU2VydmVyIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDoyNTUxMy8ifQ.aIVCsOKzBrDVZJmw7BpaNDw9Dhgnh2kNAB9_W-7Bm10)=> it return “Invalid Signature”
    Could you explain it?
    Thanks you so much!

  8. Just so you know, I had some trouble using this sample when I tried to get the ApplicationUser inside an [Authorize] method, just figured out that if you want to use ._userManager.GetUserAsync(HttpContext.User) you need to set the JwtRegisteredClaimNames.Sub to applicationUser.Id instead of applicationUser.UserName

  9. The built in DI seems to make “IOptions jwtOptions” singleton.

    That leads to this next line being the same for the entire lifetime of the application:
    public DateTime IssuedAt { get; set; } = DateTime.UtcNow;

    How do i register IOptions as Transient() in Startup.cs?

    Alternate solution is to return IssuedAt as follows:
    public DateTime IssuedAt { get { return DateTime.UtcNow; } }

    1. Hi Foobar, I suspect that the service collection does indeed only create a single instance of that object, but that has nothing to do with your problem as “singleton” is not the same as “static”. Your problem stems from the fact that you are only setting the value once.

      public DateTime IssuedAt { get; set; } = DateTime.UtcNow

      That is code that initialises an auto-property, so unless you set it again somewhere else, it won’t change 🙂

      (Note: Have a look at the code in my repo where I use an expression body as I have no setter requirement).

      1. Yeah, I took it from this blog post. The code differs from this post and the repo 🙂 check line 65 above.

  10. Hi William, I am planning to use EF Core to pass through the username and password to get a user authenticated by a stored procedure in my database. I plan on creating a Data Layer Project that will access my database models. Do you have a sample of how I can do this?

    private static Task GetClaimsIdentity(ApplicationUser user)
    {
    if (user.UserName == “MickeyMouse” &&
    user.Password == “MickeyMouseIsBoss123”)
    {
    return Task.FromResult(new ClaimsIdentity(new GenericIdentity(user.UserName, “Token”),
    new[]
    {
    new Claim(“DisneyCharacter”, “IAmMickey”)
    }));
    }

    if (user.UserName == “NotMickeyMouse” &&
    user.Password == “NotMickeyMouseIsBoss123”)
    {
    return Task.FromResult(new ClaimsIdentity(new GenericIdentity(user.UserName, “Token”),
    new Claim[] { }));
    }

    // Credentials are invalid, or account doesn’t exist
    return Task.FromResult(null);
    }

    Linda

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s