How Configure User Authentication for MQTTnet version 4 Broker?

Authentication Users an MQTT broker with C#

MQTT is a lightweight and flexible messaging protocol that is widely used for IoT applications. MQTT allows devices to communicate with each other and with a central server (broker) using topics and messages. However, MQTT does not provide any built-in security mechanisms for authentication and authorization of clients. This means that anyone who knows the broker's address and port can connect to it and publish or subscribe to any topic.

One way to enhance the security of MQTT communication is to implement user validation for the broker. User validation means that the broker will check the username and password of each client that tries to connect to it, and only allow those who have valid credentials. This way, unauthorized clients will be rejected and prevented from accessing the broker's resources.

There are different ways to implement user validation for an MQTT broker, depending on the library or framework that you use. In this blog post, we will show you how to do it using MQTTnet, a high-performance .NET library for MQTT communication. MQTTnet provides both a client and a server (broker) implementation of the MQTT protocol up to version 5.

Implementing user validation for MQTTnet broker, we need to do two things:

  1. Set up a connection validator for the broker options

  2. Define a logic for validating usernames and passwords

Let's start to do it!

Set up a connection validator for the broker options

To begin with, when need to config and set up some things on the broker. A connection validator is a delegate that is invoked by the broker whenever a new client tries to connect. The connection validator receives an object of type MqttConnectionValidatorContext as a parameter, which contains information about the client's connection request, such as its client id, username, password, protocol version etc.

The connection validator can inspect these properties and decide whether to accept or reject the client's connection by setting the ReasonCode property of the context object. The possible values for this property are:

  • Success: The client is accepted by the broker

  • UnsupportedProtocolVersion: The requested protocol version is not supported by the broker

  • ServerUnavailable: The broker is not available at this time

  • BadUserNameOrPassword: The username or password is incorrect

  • NotAuthorized: The client is not authorized to connect

To set up a connection validator for the broker, we need to assign a lambda expression or a method reference to the ValidatingConnectionAsync property of MQTT server. I continue the Simple MQTT broker which was developed in the last post.

...
var server = new MqttFactory().CreateMqttServer(options.Build());
//Add Interceptor for logging incoming messages
server.InterceptingPublishAsync += Server_InterceptingPublishAsync;
// Add connection Validator
server.ValidatingConnectionAsync += Server_ValidatingConnectionAsync;
// Start the server
await server.StartAsync();
...
Task Server_ValidatingConnectionAsync(ValidatingConnectionEventArgs arg)
{
    throw new NotImplementedException();
}

Define a logic for validating usernames and passwords

The logic for validating usernames and passwords depends on how we store them in our application. For simplicity, let's assume that we have a dictionary that maps usernames to passwords in memory:

var users = new Dictionary<string,string>(); 
users.Add("asha", "1234"); // username, password
users.Add("sepehr", "5678");

Then, our Server_ValidatingConnectionAsync method could look something like this:

Task Server_ValidatingConnectionAsync(ValidatingConnectionEventArgs arg)
{
    if(!string.IsNullOrWhiteSpace(arg.Username)&&!string.IsNullOrWhiteSpace(arg.Password))
    {
        if(!(users.TryGetValue(arg.Username, out var password) && password == arg.Password))
        {
            arg.ReasonCode = MQTTnet.Protocol.MqttConnectReasonCode.BadUserNameOrPassword;
            return Task.CompletedTask;
        }
    }
    arg.ReasonCode = MQTTnet.Protocol.MqttConnectReasonCode.BadAuthenticationMethod;
    return Task.CompletedTask;
}

Of course, this is just an example of how we can implement user validation for our broker. In reality, we might want to use more secure ways of storing and comparing passwords (such as hashing or encryption), or use external sources of authentication (such as databases or identity providers).

Summary

In this blog post, we showed you how to implement user validation for MQTTnet broker. We explained how to set up a connection validator for our broker options and how to define a logic for validating usernames and passwords based on our application requirements.

User validation is one of the ways to enhance security of MQTT communication between clients and brokers. However, it does not prevent eavesdropping or tampering with messages on transit. To protect against these threats, we recommend using Transport Layer Security (TLS) encryption along with user validation.

We hope you found this blog post useful and informative. If you have any questions or feedback about user validation with MQTTnet broker or anything else related to MQTTnet library, please feel free to comment it. Also, you can see the full code of this on the Github repository.