Client Validation Using Basic Authentication in Web API

Client Validation Using Basic Authentication in Web API

In this article, I am going to discuss how to implement Client Validation Using Basic Authentication in Web API. Please read our previous article before proceeding to this article as we are going to work the same example. In our last article, we discussed how to implement Token Based Authentication in ASP.NET Web API.

If you observed in the last article, we have created the following MyAuthorizationServiceProvider class.

Client Validation Using Basic Authentication in Web API

The first method i.e. ValidateClientAuthentication method is responsible for validating the Client, in the above example, we assume that we have only one client so we’ll always return that it is validated successfully.

Let’s change the requirement. Assume that we have more than one client, who is going to consume our service. In such a case, we need to validate the clients within the ValidateClientAuthentication method.

Let’s see how to achieve this.

For this, we are going to use the following ClientMaster table

Client Validation Using Basic Authentication in Web API

Please use below SQL Script to create and populate the ClientMaster table with some test data.

USE SECURITY_DB
GO

-- Create ClientMaster table
CREATE TABLE ClientMaster
(
  ClientKeyId INT PRIMARY KEY IDENTITY,
  ClientId VARCHAR(500),
  ClientSecret VARCHAR(500),
  ClientName VARCHAR(100),
  CreatedOn DateTime
)
GO

-- Populate the ClientMaster with test data
 INSERT INTO ClientMaster(ClientId, ClientSecret, ClientName, CreatedOn) 
 VALUES(NEWID(), NEWID(), 'My Client1', GETDATE())

 INSERT INTO ClientMaster(ClientId, ClientSecret, ClientName, CreatedOn) 
 VALUES(NEWID(), NEWID(), 'My Client2', GETDATE())

 INSERT INTO ClientMaster(ClientId, ClientSecret, ClientName, CreatedOn) 
 VALUES(NEWID(), NEWID(), 'My Client3', GETDATE())

Once you create the ClientMaster table, then you need to update the EDMX file to add the above ClientMaster table.

Create a class file with the name ClientMasterRepository.cs and then copy and paste the following code.
namespace TokenAuthenticationInWebAPI.Models
{
    public class ClientMasterRepository : IDisposable
    {
        // SECURITY_DBEntities it is your context class
        SECURITY_DBEntities context = new SECURITY_DBEntities();
        
        //This method is used to check and validate the Client credentials
        public ClientMaster ValidateClient(string ClientID, string ClientSecret)
        {
            return context.ClientMasters.FirstOrDefault(user =>
             user.ClientId == ClientID
            && user.ClientSecret == ClientSecret);
        }

        public void Dispose()
        {
            context.Dispose();
        }
    }
}

Here we create the ValidateClient method which is very straightforward. It’s the ClientID and ClientSecret as input parameter and checks in the ClientMaster table whether the client is valid or not and it simply returns the client details.

Now we need to modify the ValidateClientAuthentication() method of MyAuthorizationServerProvider class as shown below.
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
    string clientId = string.Empty;
    string clientSecret = string.Empty;
    // The TryGetBasicCredentials method checks the Authorization header and
    // Return the ClientId and clientSecret
    if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
    {
        context.SetError("invalid_client", "Client credentials could not be retrieved through the Authorization header.");
        context.Rejected();
        return;
    }
    //Check the existence of by calling the ValidateClient method
    ClientMaster client = (new ClientMasterRepository()).ValidateClient(clientId, clientSecret);
    if (client != null)
    {
        // Client has been verified.
        context.OwinContext.Set<ClientMaster>("oauth:client", client);
        context.Validated(clientId);
    }
    else
    {
        // Client could not be validated.
        context.SetError("invalid_client", "Client credentials are invalid.");
        context.Rejected();
    }
    context.Validated();
}

Note: We need to pass the ClientId and ClientSecret using the Basic authentication in the authorization header i.e. in Base64 encoded format.

Modify the GetResource1 action method of the TestController as shown below.

Client Validation Using Basic Authentication in Web API

Testing the API using Postman:

Let’s first create the Base64 Encode value by for the ClientID and ClientSecret by using the following website

https://www.base64encode.org/

Enter the ClientID and ClientSecret separated by a colon (:) in “Encode to Base64 format” textbox, and then click on the “Encode” button as shown in the below diagram which will generate the Base64 encoded value.

Client Validation Using Basic Authentication in Web API

Once you generate the Base64 encoded string, let’s see how to use basic authentication in the header to pass the Base64 encoded value.

Here we need to use the Authorization header and the value will be the Base64 encoded string followed the “BASIC” as shown below.

Authorization: BASIC QzFBMDNCMTAtN0Q1OS00MDdBLUE5M0UtQjcxQUIxN0FEOEMyOjE3N0UzMjk1LTA2NTYtNDMxNy1CQzkxLUREMjcxQTE5QUNGRg==

Let’s see step by step procedure to use the Postman to generate the Access Token

Step1:

Select the Method as POST and provide URI as shown below in the below image

Client Validation Using Basic Authentication in Web API

Step2:

Select the Header tab and provide the Authorization value as shown below.

Authorization: BASIC QzFBMDNCMTAtN0Q1OS00MDdBLUE5M0UtQjcxQUIxN0FEOEMyOjE3N0UzMjk1LTA2NTYtNDMxNy1CQzkxLUREMjcxQTE5QUNGRg==

Client Validation Using Basic Authentication in Web API

Step3:

Select the Body Tab. Then choose x-www-form-urlencoded option and provide the username and password value. Provide the grant_type value as password as shown in the below image,

Client Validation Using Basic Authentication in Web API

Now click on the Send button which will generate the access token as shown below.

Client Validation Using Basic Authentication in Web API

Once the access token is generated, we use that token to access the resources as shown below.

Client Validation Using Basic Authentication in Web API

In the next article, I will discuss how to generate Refresh Token in ASP.NET Web API. Here, in this article, I try to explain how to implement Client Validation Using Basic Authentication in Web API with an example. I hope this article will help you with your need. I would like to have your feedback. Please post your feedback, question, or comments about this article.

23 thoughts on “Client Validation Using Basic Authentication in Web API”

  1. blank

    Hi, I’ve followed this post and the previous ones, and all was ok but in this one, the Test Resource1 modified as required is not working.
    The Token method works and gives back the Token but the Claims contain only the Username and Password, they do not contain ClientID, ClientSecret, ClientName so maybe I’m doing something wrong in the Client validation that is not setting the Client Data into the claims list.
    Do you have any suggestion?
    Thanks in advance

  2. blank

    I’ve found the answer to my previous question, before using the test method it is necessary to add the properties from the Client data to the Claims of the context. My solution is the following:
    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
    UsersRepository _repo = new UsersRepository();

    var user = _repo.ValidateUser(context.UserName, context.Password);
    if (user == null)
    {
    context.SetError(“invalid_grant”, “Provided username and password is incorrect”);
    return;
    }
    var client = context.OwinContext.Get(“oauth:client”);
    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    identity.AddClaim(new Claim(ClaimTypes.Role, user.GetRolesString()));
    identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
    identity.AddClaim(new Claim(“Email”, user.Email));
    identity.AddClaim(new Claim(“FullName”, string.Format(user.FullName)));
    identity.AddClaim(new Claim(“FullLogin”, user.ToJson()));
    identity.AddClaim(new Claim(“ClientName”, client.ClientName));
    identity.AddClaim(new Claim(“ClientKeyID”, client.ClientKeyID));
    identity.AddClaim(new Claim(“ClientKeySecret”, client.ClientKeySecret));

    context.Validated(identity);

    }
    This way the properties of the client can be shown in the resource1 method. You can also put the whole class in a claim using a json serialization as I did in my user class.
    HTH
    Sabrina

    1. blank

      Thank you for your idea. It works for me. But I don’t know where is your UsersRepository come from? I only have UserMasterRepository and ClientMasterRepository. However, based on your idea. I add the clientID and ClientName to identity and finally, it works.

  3. blank

    Hi,
    How to update .edmx file. below suggestion are not working
    Suggestion 1:
    1.Build the project after updating EDMX file.
    2.Right click your .tt file in solution explorer.
    3.Select “Run Custom Tool” option

    Suggestion 2:(on right-click not getting any option like “Update Model from Database”)
    In the Model Browser, right-click the .edmx file and select Update Model from Database.
    Expand the Tables, Views, and Stored Procedures nodes, and check the objects you want to add to the .edmx file.

  4. blank

    I cant get this to work. the var identity = (ClaimsIdentity)User.Identity;
    var ClientID = identity.Claims
    .FirstOrDefault(c => c.Type == “ClientID”).Value;

    // this line always has a null value.

  5. blank

    var ClientID = identity.Claims
    .FirstOrDefault(c => c.Type == “ClientID”).Value;

    // this line always has a null value.

  6. blank

    My Solution:

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
    using (UserMasterRepository _repo = new UserMasterRepository())
    {
    var user = _repo.ValidateUser(context.UserName, context.Password);
    if (user == null)
    {
    context.SetError(“invalid_grant”, “Provided username and password is incorrect”);
    return;
    }
    var client = context.OwinContext.Get(“oauth:client”);
    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    identity.AddClaim(new Claim(ClaimTypes.Role, user.UserRoles));
    identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
    identity.AddClaim(new Claim(“Email”, user.UserEmailID));
    identity.AddClaim(new Claim(“ClientId”,client.ClientId));
    identity.AddClaim(new Claim(“ClientName”,client.ClientName));
    identity.AddClaim(new Claim(“ClientSecret”,client.ClientSecret));
    context.Validated(identity);
    }
    }

    1. blank

      var ClientID = identity.Claims.FirstOrDefault(c => c.Type == “ClientID”).Value;
      // this line always has a null value. I got the same error as well

      Tried to follow GKHN suggestion, but I I get an error at the following line when I try to update the GrantResourceOwnerCredentials

      var client = context.OwinContext.Get(“oauth:client”);
      // The type arguments for method ‘IOwinContext.Get(string)’ cannot be inferred from the usage.

      Any helps or tips is highly appreciated.

  7. blank

    This article shows how to authenticate a user. As the user works in the system updating and adding new records, how can we get the user info to add “CreatedBy” or “Updatedby” fields of out tables?

  8. blank

    var ClientID = identity.Claims.FirstOrDefault(c => c.Type == “ClientID”).Value;
    // this line always has a null value. I got the same error as well

    Tried to follow GKHN suggestion, but I I get an error at the following line when I try to update the GrantResourceOwnerCredentials

    var client = context.OwinContext.Get(“oauth:client”);
    // The type arguments for method ‘IOwinContext.Get(string)’ cannot be inferred from the usage.

    Any helps or tips is highly appreciated.

    1. blank
      George D'Souza

      var client = context.OwinContext.Get(“oauth:client”);//your code to be changed

      The solution is to change the above line of code to:
      var client = context.OwinContext.Get(“oauth:client”);

  9. blank

    var client = context.OwinContext.Get[ClientMaster](“oauth:client”)

    [ClientMaster]:
    change [ and ] to “less then” sign and “greater then” sign.

  10. blank

    the comment removed my generic type. after GEt you need have a generic type of ClientMaster, to convert oauth:client to ClientMaster type

  11. blank

    also make sure it is ClientId not ClientID, the screen copy provided by Author is ClientID but in the database field is ClientId so the ClientMaster uses ClientId, it is case sensitive. C# cannot map them

Leave a Reply

Your email address will not be published. Required fields are marked *