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.
This post is the second part of 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.
Part I addressed how you could issue the JSON Web Tokens and, in this part, I will cover the authorisation aspects.
This post is therefore organised as follows:
- Configuration – addresses what needs to be added to the middleware and services in order for the auth setup to work
- You Shall Not Pass! – I couldn’t help myself, but yes, access control!
In order to make sense of this post, you’d most likely need to have read Part I, however, if you would prefer just getting straight to the code, you can download/fork the example project and reference the relevant sections as we go.
First things first, we need to add a claims-based authorisation policy. This is easily done in the ConfigureServices method in Startup.cs
What this does is add a policy named DisneyUser, with the requirement that the DisneyCharacter claim on the incoming token payload have the value of IAmMickey (I will get to how the policy is applied a little bit later).
The next thing that is required, is to tell ASP.NET that incoming requests might contain JWTs. Fortunately, there is middleware support for this (although it does require that you add the Microsoft.AspNetCore.Authentication.JwtBearer package as a dependency in your project.json file).
Adding middleware is done in the Configure method of Startup.cs and since this is driving authorisation, it needs to be added pretty much first in the middleware pipeline (in case you did not know this, the order in which you add middleware is important):
- Lines 8 – 23: sets up the validation parameters that we’re going to pass to ASP.NET’s JWT bearer authentication middleware (there are many more options available than what are utilised here, for reference, TokenValidationParameters live in the Microsoft.IdentityModel.Tokens namespace). I believe the parameters set in this example are reasonably self-explanatory, but if anything is unclear, feel free to ask in the comments.
- Lines 25 – 30: add the JWT token bearer middleware that tells the application that we expect JWT tokens as part of the authentication and authorisation processes and to automatically challenge and authenticate.
That’s it for configuration, next up, restricting access to controllers with authorisation policies.
You Shall Not Pass!
- In Part I, I set up claims identities in JwtController.cs and gave the user MickeyMouse, a claim named DisneyCharacter with the value IAmMickey (refer back to lines 110 – 134 of that file).
- In the Configuration section above, I added a DisneyUser authorisation policy to the services collection.
In order to test the authorisation setup, we need a controller that can serve our requests. For this, I created a very basic JwtAuthTestController
- Line 7: take note of the route configuration for the controller
- Lines 20 – 32: this is the only method on this controller
- Line 20: tell the application that this method expects GET requests
- Line 21: tell the authentication middleware to apply the DisneyUser authorisation policy to this mehod. This will ensure that ONLY bearers of JWTs that fulfill the claim requirements that we set up in Configuration are allowed access to this method
- Lines 22 – 32: execute some basic logic in the controller method and return a response.
(The basic test setup is going to be the same as for that in Part I. For ease of reference, I repeat the instructions here)
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
Before we can test the access control, we need a bearer token to add to our requests.
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:
As you can see, the token expires in 5 min (300 seconds), so you need to move fast! (OK, not really, you can always just send another request, or even change the JwtIssuerOptions.ValidFor setting and recompile, so don’t stress)
Copy the token (everything between the “”s for access_token) and create another request in Postman, but this time a GET. Provide the relevant request endpoint (URL) which, if you are using the sample application, is http://localhost:1783/api/test and, under the Headers tab (not Authorization!) add a key/value pair where the key is Authorization (NB! Take note of the American spelling!) and the value is ‘Bearer blahblahblahyourtokencontenthereblahblahblah’. In other words, you need to provide, as key, the word Bearer followed by a single white space, followed by the content of the access_token value you copied above response above (excluding the “”s).
In the screenshot, the token is cut off, but it looks something like this in plain text:
Note: this value will obviously differ every time you request a token, so please do not use this and expect it to work, you must use the token your token server provides you with!
If everything was set up correctly, you should receive a response such as the one below (check out the Body)
OK, so this is all nice and well, the user we expected to have access to that method, had access to that method, but now we also need to confirm that users who do not have the necessary claim credentials are denied access.
Following pretty much the exact same steps as above, set up a POST method for our unauthorised user (note that this user is authenticated, i.e. a valid user, but unauthorised, in other words, although the user is a legitimate user, he/she does not have permission to access the method under test).
The user we set up for this is NotMickeyMouse (refer again to GetClaimsIdentity in JwtController)
Once again, copy the bearer token into the Authorization header for a GET request (you can use the exact same GET as before and simply replace the Bearer with the one you get back from NotMickeyMouse). This time, however, you will notice that access is denied.
And that, ladies and gentlemen, is ASP.NET’s identity middleware taking care of access control based on JSON Web Tokens through a claims-based authorisation policy!
I recognise that the above could be a touch confusing if you have never worked with Postman or don’t fully understand how the HTTP requests are set up, so please do not hesitate to ask in the comments below if anything is unclear. I will do my best to shed further light on any issues you might encounter.
(If you got this far and liked what you read, consider following me @thewillhallatt if you would like to be notified of future articles)