Productivity Tools

Tools written by an IT business manager, a passionate developer.

OAuth ClientCredentials

Adding OAuth to the application is described on multiple sites, but I am missing a very simple tutorial without explaining flows.

For application to application communication we are using Client Credentials flow.

Identity server

First, we need to add API definition”


public static IEnumerable<ApiResource> Apis => new List<ApiResource>
{
    new ApiResource("GetTask3.API", "API for GetTask3 Application")
};

Next, we need to add the client and add in the scope, the value defined earlier.

new Client
{
    ClientId = "GetTask3Cmdlet",
    AllowedGrantTypes = GrantTypes.ClientCredentials,
    ClientSecrets =
    {
        new Secret(configuration["GetTask3Cmdlet"].Sha256())
    },
    AllowedScopes = { "GetTask3.API" }
},

Application

Now let’s test if the communication between applications is working. Then let’s break it and repair it.

Package needed

microsoft.aspnetcore.authentication.jwtbearer

Service

In the void ConfigureServices(IServiceCollection services) section

services.AddAuthentication(options =>
    {
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    }).AddJwtBearer(options =>
    {
    options.Authority = "https://identityserver.productivitytools.tech:8010";
    options.Audience = "GetTask3.API";
    });

Be sure that you have the following middlewares in the Configure method (order is important)

app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

Use Authentication

In the configure method.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
   ... 
   app.UseRouting();
   app.UseAuthorization();
   ...
}

Method

Add Authorize attribute.

[HttpPost]
[Authorize]
[Route(Consts.TodayList)]
public ElementView GetTasks([FromBody]ListRequest request = null)
{
    ...
}

After this operation, you should receive 401 when calling the endpoint

Client

Required packages – IdentityModel

We need to send the token with each request. To generate we need to call Identity Server.

private string token;
private string Token
{
    get
    {
        if (string.IsNullOrEmpty(token))
        {
            var client = new HttpClient();

            var disco = client.GetDiscoveryDocumentAsync("https://identityserver.productivitytools.tech:8010/").Result;
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
            }

            var tokenResponse = client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                Address = disco.TokenEndpoint,

                ClientId = "GetTask3Cmdlet",
                ClientSecret = configuration["GetTask3Cmdlet"],
                Scope = "GetTask3.API"
            }).Result;

            if (tokenResponse.IsError)
            {
                Console.WriteLine(tokenResponse.Error);
            }

            Console.WriteLine(tokenResponse.Json);
            token = tokenResponse.AccessToken;
        }
        return token;
    }

The last step is to add a Bearer token before calling the endpoint

client.SetBearerToken(Token);

After those steps application should call the service again without issues.