In this episode, we look at the group management service, and the changes required for it to enforce the requests authentication using an access token (JWT).
For the walk-through you can check out the next video, but if you prefer a quick read, skip to the written synthesis.
The playlist for the whole series is here.
In the last post, we’ve seen how to configure IdentityServer4 in the auth service. In this post, we take advantage of ASP.NET Core built-in features to authenticate requests to the group management API using JWT (JSON Web Tokens) provided by the auth service to a client application, after a successful authentication.
Configuring authentication and authorization
Configuring the application to require JWT authentication is rather simple, almost like magic 😛, because ASP.NET Core comes prepared to handle such scenarios out of the box. We’ll start by seeing how to perform these configurations, but later on we’ll try to shed some light on some of the magic.
Setting up JWT authentication
Configuring authentication will require the usual 2 steps in the
Startup class (or methods called by it): configuring services and configuring the request handling pipeline.
Starting with the simplest part, the request handling pipeline, we just need to add
app.UseAuthentication(), much like we did when configuring authentication in the auth service.
Now let’s move to the service configuration. We have a
ServiceCollectionExtensions class to where we have been extracting the methods that configure the services, so we’ll create a new one named
AddConfiguredAuth in there (although this should be refactored later, to avoid having all the unrelated configurations in the same place).
Looking at the code above, I think it’s easy to see why I said it was simple to implement, 4 or 5 lines of code take care of everything (because ASP.NET Core implements the hard parts of course).
Let’s quickly go through what’s going on:
- We call
AddAuthenticationto add the core required services for authentication, along with the default scheme we want to use for authentication.
- We call
AddJwtBearerto add the required services for JWT authentication. We provide the scheme name, so it can be matched by what we passed to
AddAuthenticationand also provide some options for handling the JWTs.
Authorityis the url of the auth service, so the application can fetch some required information to validate the tokens.
Audienceis used in the token validation to ensure the token was intended to be used by this specific application.
At first glance one might ask, how is this enough to validate the tokens? Even though it might not seem a lot, the
Authority plays a huge role in this, as OpenId Connect specs include discovery of information about the provider, meaning the OpenId Connect provider exposes well known endpoints where the relying parties can fetch information. We’ll see an example in a coming section.
Setting up authorization based on the authenticated user
Basically we require a user to be authenticated and have a scope named
GroupManagement to be authorized to access the API. We could use different scopes for different endpoints, but no need to go down that path for now.
To perform these configurations we go to the
ServiceCollectionExtensions.AddRequiredMvcComponents method and make some additions:
We saw similar code in episode 019, but for a quick overview, we’re building an authorization filter/policy to add to MVC’s filters. Building the policy we indicate what we require, which is the user to be authenticated and have a claim named
scope with the value
GroupManagement. Given that in the JWT validation we’re ensuring
GroupManagement is a target audience, this scope check could probably be skipped in this simple scenario, using it if we want to have multiple scopes in the same API like mentioned previously.
OpenId Connect configuration discovery endpoint
I won’t even try to go into much detail on OpenId Connect discovery, as I don’t really have a complete grasp of the whole protocol, but I think it’s interesting to have some understanding about what’s going on and not just rely on the “magic” that happens with 4 or 5 lines of code.
As I mentioned previously, providing the auth service url to the JWT validation services goes a long way because OpenId Connect specifies ways of using well known endpoints to gather required information.
If we grab the auth service url and append to it
/.well-known/openid-configuration we get a
JSON response with the aforementioned information.
I cut off a bit of content to avoid a massive wall of
JSON, but wanted to point out some interesting bits:
- the endpoints the provider exposes are indicated here
jwks_uriendpoint provides a set of public keys that the applications can use to validate the JWTs created by the auth service, signed by its private key
- besides endpoints, there are indications of capabilities supported, like
frontchannel_logout_supported, the scopes and claims supported, etc
Since we’re checking out some “behind the scenes” stuff that we could ignore, as it’s mostly handled for us, but it’s always good we know what’s going on in our applications, we can take a look at a sample JWT.
Remember the JWT is not encrypted, just signed so any tampering is detected, so we can grab it and check out what’s in there. If we grab a JWT and put it in jwt.io, we can see its data.
Won’t go through the whole thing, but we can take a look at some familiar things:
client_idwe can see that the token was emitted for usage by the
- we can see a familiar audience in the
- in the
scopearray we see the scopes we discussed in the previous post
That should do it of integration of JWT based authentication in the group management API. As we saw, being IdentityServer the provider or something else is irrelevant from the point of view of this API, as long as it provides the required features.
Links in the post:
- OpenId Connect Discovery
- Episode 019 - Roles, claims and policies - ASP.NET Core: From 0 to overkill
- Episode 016 - Authentication with Identity and Razor Pages - ASP.NET Core: From 0 to overkill
The source code for this sub-series of posts is scattered across a bunch of repositories in the “Coding Militia: ASP.NET Core - From 0 to overkill” organization, tagged as
Sharing and feedback always appreciated!
Thanks for stopping by, cyaz!