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.
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:
- 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
- Issuing a JSON Web Token – which focuses on just that as well as how you can validate that it all works.
- What to expect in Part II
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.
- 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).
- 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.
- That you know what JSON Web Tokens are
- That you know how to create a Web API project with ASP.NET Core MVC
- 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)
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.
- Fire up the example solution/your application
- If you are using the example solution, the application’s URL is http://localhost:1783/ (configured in launchSettings.json)
- 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)
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:
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)
(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.
- Token Authentication in ASP.NET Core (without this blog post by Nate Barbettini, this multi-part tutorial of mine would not have been possible)
- Supported Token and Claim Types (although aimed at Azure and ADAuth specifically, the first part is a useful, general overview of tokens
- ASP.NET Core Authorization Lab