This guide provides a step-by-step explanation of how to implement token-based authentication and authorization in a .NET Console Application using Entrypage.io as your identity provider.

Prerequisites:

Obtaining a token in a console application depends on its ability to securely store a secret. Console apps can serve different purposes; for example, one might run as a background job, while another could be a widely distributed tool. Depending on the scenario, a console application is considered either a public or a confidential client.

  • When a console application is distributed to a number of people on untrusted devices, it should be considered a public client. In this case, it should use the Authorization Code Grant with Proof Key for Code Exchange (PKCE).
  • When a console application runs in the background, it is considered a confidential client and should use the Client-Credentials Grant.

Implementing the Client-Credentials Grant

To authenticate as a confidential client, you obtain a token using the Client-Credentials Grant. This involves posting the client_id and client_secret to the /token endpoint.

To obtain a token, the request must contain:

  • A Basic Auth header, which is a Base64-encoded client_id:client_secret pair.
  • A request body that includes the requested scope, with a minimum of ‘openid’.

It’s important to understand that when a token is obtained through the Client-Credentials Flow, the token does not represent a user but a client (typically a machine). As such, the subject identifier is the client ID, never a user ID.

1. Configure the Authorization Server

To set up your authorization server with Entrypage.io, follow these steps:

  1. Go to portal.entrypage.io and sign in to your account.
  2. Navigate to the Clients tab and create a new client.
  3. Configure the client with Client-Credentials enabled.
  4. Configure the client with a Client Secret.
  5. Set the client_id to console-app.

Once this is complete, you are ready to configure your application.

2. Create a New Console Application

While it is possible to obtain a token through executing a web-request, is is best practice to use a library to obtain the token for you and create the request correctly, hence, creating the console application project consists of the foollowing steps:

dotnet new console
dotnet add package Duende.IdentityModel.OidcClient

3. Obtain The Discovery Document (Optional)

A token is obtained from the token endpoint. The location of this endpoint is documented in the server’s /well-known/openid-configuration file, also known as the discovery document.

The URL for the token endpoint rarely changes. The best practice, or “royal way,” to get the token endpoint’s address is by first obtaining the discovery document. However, it’s not uncommon for developers to use the token endpoint’s address directly if they already know it.

You can obtain the discovery document by executing the following C# code:

var discoveryDocument = await httpClient.GetDiscoveryDocumentAsync(authority);

4. Request the Token

While you could execute the request using the HttpClient class, this is considered a bad practice. Instead, you should use a common, trusted library such as Duende.IdentityModel.OidcClient to handle the request for you.

The library’s HttpClient extension provides a simplified method for making the request:

var token = await httpClient.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest()
{
    Address = discoveryDocument.TokenEndpoint,
    ClientId = clientId,
    ClientSecret = clientSecret,
    Scope = "openid"
});

Validating the signature

To validate a JSON Web Token’s (JWT) authenticity, an application must verify its signature. This ensures the token hasn’t been tampered with and was issued by a trusted party.

However, in this specific scenario, the console application acts as a client that receives a token and then forwards it to a resource server to access a resource. In this standard OAuth 2.0/OpenID Connect flow, the resource server is the entity responsible for validating the token’s authenticity. The console app, acting as a client, simply presents the token; it doesn’t need to validate its signature.

Demo

Find a complete example of how to implement the client-credentials grant in a .NET Console application on GitHub.