Identity Server 4 ClientCredentials with POSTMAN
This tutorial will demonstrate how to set up security within microservices using Identity Server 4 with OpenID. This will use a Client and Secret for microservice to microservice (machine-to-machine) communication that way a compromised microservice can’t interact with resources it’s not authorized to. I will also demonstrate how to use POSTMAN to get tokens, inspect tokens and verify things are set up correctly.
GitHub
GitHub: Identity Server 4 OpenID POSTMAN
What is OpenID Connect (OIDC)?
OpenID is a protocol that standardized OAuth and added certain capabilities to make authentication easier and more universal. OAuth is still responsible for handling authorization while OpenID is an extension that specifically standardizes authentication by providing login and profile information through a token known as the JWT token.
Setting Up the Identity Server
This section will walk through creating the Identity Server 4 project and how to configure it for OpenID Connect.
Creating the Project
First you’ll need to install the Identity Server 4 templates.
dotnet new -i identityserver4.templates
After the templates are installed you can create an Identity Server project using dotnet new
. If you want to use OAuth for authenticating users you can also add the UI which will include MVC controllers and views. This is not necessary for this tutorial.
1 2 3 4 5 6 7 8 |
dotnet new sln -n CoreMS.IdentityServer mkdir src cd src dotnet new is4empty -n CoreMS.IdentityServer # optional, will install mvc controllers and views for user authentication. # this is not necessary for inner cluster authentication. dotnet new is4ui -n CoreMS.IdentityServer |
Setting up API Resources, Clients in the Config.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
public static class Config { public static IEnumerable<IdentityResource> IdentityResources => new IdentityResource[] { new IdentityResources.OpenId() }; public static IEnumerable<ApiResource> ApiResources => new ApiResource[] { new ApiResource("addressvalidator", "CoreMS APIs") { Scopes = { "addressvalidator.fullaccess" } } }; public static IEnumerable<ApiScope> ApiScopes => new ApiScope[] { new ApiScope("addressvalidator.fullaccess"), }; public static IEnumerable<Client> Clients => new Client[] { new Client { ClientName = "CoreMS Machine 2 Machine Client", ClientId = "coremsm2m", ClientSecrets = { new Secret("78195A38-796A-4EE0-8F2E-8F4EB3FECF34".Sha256()) }, AllowedGrantTypes = GrantTypes.ClientCredentials, AllowedScopes = { "addressvalidator.fullaccess" } } }; } |
Startup.cs
Under the ConfigureService()
method you will also need to add the Config.ApiResources
to register them with the Identity Server.
Add this line of code .AddInMemoryApiResources(Config.ApiResources)
.
1 2 3 4 5 6 7 8 |
var builder = services.AddIdentityServer(options => { // see https://identityserver4.readthedocs.io/en/latest/topics/resources.html options.EmitStaticAudienceClaim = true; }) .AddInMemoryIdentityResources(Config.IdentityResources) .AddInMemoryApiScopes(Config.ApiScopes) .AddInMemoryClients(Config.Clients); |
Microservice API
The goal here is to protect a microservice API from internal abuse within the cluster by configuring JWT bearer verification. The general idea of protecting microservice-to-microservice (machine-to-machine) communication is to limit the amount of damage a bad actor could do if they hypothetically gained access to the cluster. This could be a hacker compromising a container and attempting to interact with other microservices in an effort to pivot or gain information.
Install NuGet Package
Microsoft.AspNetCore.Authentication.JwtBearer
Configuring JWT Bearer Verification
There are several ways to set up JWT validation through .NET. I will demonstrate how to do this using the ASP.NET middleware libraries.
Startup.cs – ConfigureServices()
1 2 3 4 5 6 |
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = "https://localhost:5001"; options.Audience = "corems"; }); |
To apply authentication to the entire API it’s easiest to create an Authorization Policy and apply it as an AuthorizeFilter.
1 2 3 4 5 6 7 8 9 10 |
// authentication policy var authPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); services.AddControllers(configure => { configure.Filters.Add(new AuthorizeFilter(authPolicy)); }); |
Startup.cs – Configure()
Add in the code below to the Configure()
method. If you skip this step or comment this out the Identity Server will create a valid JWT token but it will still return unauthorized when using that valid token against the API service.
1 |
app.UseAuthentication(); |
Using POSTMAN to Verify OpenID/OAuth Works
POSTMAN is a great tool for interacting with APIs and has full support for OpenID/OAuth.
Creating a GET Request
We will first need to set the URL to GET to https://localhost:5011/WeatherForecast
You may need to update the ports here but this is the port for the microservice and can be found in the Properties of the project. This should fail with a 401 Unauthorized
HTTP status response. This is as expected.
Getting a Token
In order to get a JWT token (Bearer Token), you will need to select the Authorization Tab and set it to OAuth 2
and configure it with the settings below. You may have to scroll down on the right to get to this section but look for “Configure New Token”. Be sure to set the Client ID, Secret, and Scopes requested.
The next window that will popup displays that the token has been generated and authorization with the Identity Server was successful. Click “proceed” or just wait…
On the next screen you should copy the JWT Token so you can inspect it at jwt.io.
Great Success!
At this point the Bearer Token (JWT) is being sent along with the request to get WeatherForecasts and is successfully authenticating.
Inspecting Tokens
Inspecting the JWT Token is easy. Hop over to jwt.io and paste in the JWT Token and you can see the properties passed with it.
Reserved Claims
These are the reserved claims that are used for OpenID to process and authenticate JWT tokens.
- iss – Issuer of the JWT
- sub – Subject of the JWT
- aud – Audience (Defined under ApiResources in Identity Server)
- exp – Expiration time in Epoch time.
- nbf – Not before time
- iat – Issued at time
- jti – Unique identifier for the JWT Token (JWT ID).
Further Reading
https://developer.okta.com/blog/2019/10/21/illustrated-guide-to-oauth-and-oidc
https://openid.net/
https://auth0.com/docs/tokens/json-web-tokens/json-web-token-claims