Authenticating Client With SSL/TLS Certificate
- Overview
- One-way SSL/TLS communication
- Two-way (mutual) SSL/TLS communication
- Mosquitto MQTT bridge to Kaa
Time to complete: 10 min.
Overview
In this article, you will discover how to:
- communicate with the platform over one-way and two-way (mutual) MQTT over SSL/TLS
- authenticate client (device) using X.509 certificate
- suspend/revoke/reactivate client X.509 certificate
One-way SSL/TLS communication
In one-way SSL, it is the task of the client to validate the server and ensure that the received data comes from the right source.
After accepting the connection on MQTT over a TLS port (8883 by default), the Kaa server sends its public certificate to the client.
Then the client validates the received certificate through either a certification authority (CA) or its own trust store.
Playbook
Let’s play with one-way SSL/TLS communication by connecting an MQTT client to the 8883 port, which serves MQTT over TLS.
Do not confuse 8883 with the 1883 port, because, 1883 serves plain, non-encrypted MQTT.
We assume that you have already created an application, application version, and endpoint with a token while following the “connecting your first device” tutorial. You can reuse them or create new ones.
Start by logging into your Kaa Cloud account.
To obtain the Kaa server root certificate, go to the Device management, then Credentials, click Get root certificate, and copy the certificate content.

Create a file named ca.pem in your file system and paste the copied root certificate into the file.
To run the below MQTT client on your PC, you will need Python 3 installed.
To speed things up a little, you may also just open it on Repl.it, and paste the copied certificate there, into the empty file ca.pem.
The below client was taken from the “Collecting data from a device” tutorial and upgraded to communicate over MQTT over SSL/TLS.
Create the client.py file with the below content and place it in the same folder as ca.pem.
# Simple MQTT-based one-way SSL/TLS client for the Kaa IoT platform.
import json
import random
import signal
import string
import time
import paho.mqtt.client as mqtt
KPC_HOST = "mqtt.cloud.kaaiot.com" # Kaa Cloud MQTT host
KPC_PORT = 8883 # Kaa Cloud MQTT over SSL/TLS port
ENDPOINT_TOKEN = "" # Paste your endpoint token
APPLICATION_VERSION = "" # Paste your application version
class DataCollectionClient:
def __init__(self, client):
self.client = client
self.data_collection_topic = f'kp1/{APPLICATION_VERSION}/dcx/{ENDPOINT_TOKEN}/json'
def connect_to_server(self):
print(
f'Connecting to Kaa server at {KPC_HOST}:{KPC_PORT} using application version {APPLICATION_VERSION} and endpoint token {ENDPOINT_TOKEN}')
self.client.connect(KPC_HOST, KPC_PORT, 60)
print('Successfully connected')
def disconnect_from_server(self):
print(f'Disconnecting from Kaa server at {KPC_HOST}:{KPC_PORT}...')
self.client.loop_stop()
self.client.disconnect()
print('Successfully disconnected')
def compose_data_sample(self):
return json.dumps([{
'timestamp': int(round(time.time() * 1000)),
'temperature': random.randint(15, 25),
'humidity': random.randint(35, 60),
}])
def on_message(client, userdata, message):
print(
f'<-- Received message on topic "{message.topic}":\n{str(message.payload.decode("utf-8"))}')
def main():
# Initiate server connection
client = mqtt.Client(
client_id=''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)))
data_collection_client = DataCollectionClient(client)
data_collection_client.connect_to_server()
client.on_message = on_message
client.tls_set(ca_certs="ca.pem")
# Start the loop
client.loop_start()
# Send data samples in loop
listener = SignalListener()
while listener.keepRunning:
payload = data_collection_client.compose_data_sample()
result = data_collection_client.client.publish(
topic=data_collection_client.data_collection_topic, payload=payload)
if result.rc != 0:
print('Server connection lost, attempting to reconnect')
data_collection_client.connect_to_server()
else:
print(
f'--> Sent message on topic "{data_collection_client.data_collection_topic}":\n{payload}')
time.sleep(3)
data_collection_client.disconnect_from_server()
class SignalListener:
keepRunning = True
def __init__(self):
signal.signal(signal.SIGINT, self.stop)
signal.signal(signal.SIGTERM, self.stop)
def stop(self, signum, frame):
print('Shutting down...')
self.keepRunning = False
if __name__ == '__main__':
main()
Now you should have a folder with two files—one with the Kaa server root certificate (ca.pem) and the other with the Python MQTT client (client.py).

Initialize the ENDPOINT_TOKEN variable with the endpoint token, APPLICATION_VERSION with the endpoint application version, and run the client.py Python script.
Verify that the telemetry chart on the device dashboard contains data.

Congrats, you have set up one-way SSL/TLS communication! It’s time to upgrade your skills and master two-way SSL/TLS communication, which is even more secure.
Two-way (mutual) SSL/TLS communication
In the case with two-way SSL, both the client and the server authenticate each other to ensure that both parties involved in the communication can be trusted. Both parties share their public certificates with each other and then perform mutual verification/validation. With the mutual SSL/TLS communication feature enabled, the Kaa server starts data exchange only with those clients that presented a Kaa-trusted certificate.
Playbook
To enable the mutual SSL/TLS communication feature, go to the Device management, then Credentials, then the TLS client certificates tab, click shield icon, and turn on the TLS client certificate authentication for the MQTT/TLS transport.

Now that the feature is enabled, Kaa immediately drops connections with those clients that start data exchange without presenting a trusted X.509 certificate.
To generate a Kaa-trusted X.509 certificate/key pair, click Add TLS client certificate, enter optional Common Name (CN) and TTL, and click Create.

The pop-up with a certificate chain and a private key must appear.

Create the file named client.crt in your file system and add there the content of the Certificate chain field from the pop-up.
Then, create the file named client.key and add there the content of the Private key field from the pop-up.
We assume that you have already created the ca.pem with the Kaa server root certificate as described above in the one-way SSL/TLS communication section, so create it if you haven’t done it yet.
To run the below MQTT client on your PC, you will need Python 3 installed.
To speed things up a little, you may also just open it on Repl.it, and paste the copied server root certificate, client certificate, and private key there into empty files named ca.pem, client.crt and client.key, respectively.
Create the client.py file with the below content and place it in the same folder as ca.pem, client.crt and client.key.
# Simple MQTT-based one-way SSL/TLS client for the Kaa IoT platform.
import json
import random
import signal
import string
import time
import paho.mqtt.client as mqtt
KPC_HOST = "mqtt.cloud.kaaiot.com" # Kaa Cloud plain MQTT host
KPC_PORT = 8883 # Kaa Cloud plain MQTT port
ENDPOINT_TOKEN = "" # Paste your endpoint token
APPLICATION_VERSION = "" # Paste your application version
class DataCollectionClient:
def __init__(self, client):
self.client = client
self.data_collection_topic = f'kp1/{APPLICATION_VERSION}/dcx/{ENDPOINT_TOKEN}/json'
def connect_to_server(self):
print(
f'Connecting to Kaa server at {KPC_HOST}:{KPC_PORT} using application version {APPLICATION_VERSION} and endpoint token {ENDPOINT_TOKEN}')
self.client.connect(KPC_HOST, KPC_PORT, 60)
print('Successfully connected')
def disconnect_from_server(self):
print(f'Disconnecting from Kaa server at {KPC_HOST}:{KPC_PORT}...')
self.client.loop_stop()
self.client.disconnect()
print('Successfully disconnected')
def compose_data_sample(self):
return json.dumps([{
'timestamp': int(round(time.time() * 1000)),
'temperature': random.randint(15, 25),
'humidity': random.randint(35, 60),
}])
def on_message(client, userdata, message):
print(
f'<-- Received message on topic "{message.topic}":\n{str(message.payload.decode("utf-8"))}')
def main():
# Initiate server connection
client = mqtt.Client(
client_id=''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)))
data_collection_client = DataCollectionClient(client)
data_collection_client.connect_to_server()
client.on_message = on_message
client.tls_set(ca_certs="ca.pem", certfile="client.crt", keyfile="client.key")
# Start the loop
client.loop_start()
# Send data samples in loop
listener = SignalListener()
while listener.keepRunning:
payload = data_collection_client.compose_data_sample()
result = data_collection_client.client.publish(
topic=data_collection_client.data_collection_topic, payload=payload)
if result.rc != 0:
print('Server connection lost, attempting to reconnect')
data_collection_client.connect_to_server()
else:
print(
f'--> Sent message on topic "{data_collection_client.data_collection_topic}":\n{payload}')
time.sleep(3)
data_collection_client.disconnect_from_server()
class SignalListener:
keepRunning = True
def __init__(self):
signal.signal(signal.SIGINT, self.stop)
signal.signal(signal.SIGTERM, self.stop)
def stop(self, signum, frame):
print('Shutting down...')
self.keepRunning = False
if __name__ == '__main__':
main()
Now you should have a folder with four files:
- Kaa server root certificate -
ca.pem - client certificate -
client.crt - client private key -
client.key - Python MQTT client -
client.py

Initialize the ENDPOINT_TOKEN variable with the endpoint token, APPLICATION_VERSION with the endpoint application version, and run the client.py Python script.
Verify that the telemetry chart on the device dashboard contains data.

TLS client certificate state management
Client X.509 (TLS) certificates can have one of the below states:
- Inactive is the initial state for a newly provisioned certificate that has not yet been used to authenticate a client.
- Active is the state to which the certificate automatically moves after it was first used for the client authentication. A certificate can be suspended or revoked from the active state.
- Suspended state is for a temporarily disabled certificate. Kaa rejects authentication requests with a suspended certificate. A suspended certificate can be re-activated.
- Revoked state is the terminal state for a certificate that is no longer valid.
Client Credentials Management service (CCM) provides API for issuing client X.509 certificates. A typical certificate chain is illustrated below.
- Root CA is an optional (but recommended) CA. It is not available to CCM, and you would usually keep it offline. You use Root CA to issue the platform instance CA.
- Kaa platform instance CA is the CA made available to CCM together with the private key. CCM uses this CA to issue tenant root CAs.
- Tenant root CA is a CA that gets automatically issued to each individual tenant. CCM safely stores both the certificate and the private key in Vault and uses this CA to issue client certificates.
- Client certificate is the actual certificate tenant devices connect with. CCM issues these certificates using Vault in response to a REST API call. It does not store the client certificate private key, though—only the certificate metadata.
Go to the Device management, then Credentials, find the recently generated certificate that is used by the running MQTT client, and suspend it.

Check the running MQTT client, it must be disconnected. Note that the platform automatically disconnects all clients that were using a certificate in the moment of its suspension or revocation.
Mosquitto MQTT bridge to Kaa
In some scenarios, your devices may only support plain MQTT (no TLS) or use custom topic structures that differ from the Kaa protocol topics. A common solution is to run a local Mosquitto MQTT broker configured as a bridge. It accepts plain MQTT connections from your devices on the local network and forwards messages to the Kaa platform over a secure mutual TLS connection.
We assume that you have already obtained the Kaa server root certificate (ca.crt) as described in the one-way SSL/TLS communication section and generated a client certificate/key pair (client.crt, client.key) as described in the two-way SSL/TLS communication section.
Also, you will need Docker and Docker Compose installed to run the bridge.
Start by creating the mosquitto.conf file with the below content.
listener 1883
allow_anonymous true
connection kaaiot
address mqtt.next.kaaiot.com:8883
# Topic mapping: local topic -> Kaa Protocol topic
# Format: topic <pattern> <direction> <QoS> <local-prefix> <remote-prefix>
# Replace <app-version-name> with your application version name,
# <endpoint-token> with the endpoint token.
topic "" both 0 devices/data kp1/<app-version-name>/dcx/<endpoint-token>/json/42
# Mutual TLS authentication
bridge_cafile /mosquitto/certs/ca.crt
bridge_certfile /mosquitto/certs/client.crt
bridge_keyfile /mosquitto/certs/client.key
try_private false
cleansession true
notifications false
The topic directive controls how messages are translated between the local broker and the Kaa platform.
The format is topic <pattern> <direction> <QoS> <local-prefix> <remote-prefix>.
Replace <app-version-name> with your application version name and <endpoint-token> with the endpoint token.
You can add multiple topic directives to map different local topics to different endpoints or Kaa services.
Create a Dockerfile with the below content.
FROM eclipse-mosquitto:2.0
COPY mosquitto.conf /mosquitto/config/mosquitto.conf
EXPOSE 1883
CMD ["mosquitto", "-c", "/mosquitto/config/mosquitto.conf"]
Create docker-compose.yml with the below content.
services:
mqtt:
build: .
container_name: mqtt-kaaiot-bridge
hostname: mosquitto
restart: unless-stopped
volumes:
- ./certs:/mosquitto/certs:ro
ports:
- "1883:1883"
Now you should have a folder with six files:
- Kaa server root certificate -
certs/ca.crt - client certificate -
certs/client.crt - client private key -
certs/client.key - Mosquitto configuration -
mosquitto.conf - Dockerfile -
Dockerfile - Docker Compose file -
docker-compose.yml
Update the topic directive in mosquitto.conf with your application version name and endpoint token, then start the bridge:
docker compose up -d
Verify the bridge is running with docker logs mqtt-kaaiot-bridge.
You should see a log message indicating a successful connection to the Kaa platform.
Test by publishing a message to the local broker:
mosquitto_pub -h localhost -p 1883 -t "devices/data" -m '{"temperature": 23}'
Verify that telemetry data appears on the endpoint dashboard in Kaa Cloud.
NOTE: The local broker is configured with
allow_anonymous trueand no TLS, which is suitable for trusted local networks. If your local network is not trusted, consider adding authentication and/or TLS to the local listener as well.