MQTT brokers are often secured with username/password authentication, but for device-to-cloud communication, this presents challenges: managing credentials on potentially millions of devices, securely storing them, and rotating them. OAuth2 token-based authentication offers a more robust and scalable solution, allowing devices to authenticate using short-lived access tokens issued by an authorization server.

Let’s see this in action. Imagine a device needs to connect to an MQTT broker secured with OAuth2.

First, the device, acting as a client, needs to obtain an access token from an authorization server. This typically involves a grant type like client_credentials or password (where the device’s own credentials are used to get a token, not user credentials).

# Example using curl to get a token (authorization server specific)
curl -X POST \
  https://auth.example.com/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=your_device_client_id" \
  -d "client_secret=your_device_client_secret"

The response would look something like this:

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJzY29wZSI6Im1xdHQuY29ubmVjdCIsImV4cCI6MTUxNjI0MDIyMn0.SflKxwRJSMeKK924qB_-----",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "mqtt.connect"
}

This access_token is then used to authenticate with the MQTT broker. The MQTT broker is configured to trust the authorization server and validate incoming tokens. This validation typically involves checking the token’s signature, expiration, and issuer, and ensuring it has the necessary scopes (e.g., mqtt.connect).

The device’s MQTT client library will be configured to include this token in the connection handshake. For many MQTT clients, this means passing it as part of the username or password field, or via a custom header if the library supports it.

# Example using paho-mqtt Python client
import paho.mqtt.client as mqtt

client = mqtt.Client()

# Obtain token first (as shown in curl example)
access_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJzY29wZSI6Im1xdHQuY29ubmVjdCIsImV4cCI6MTUxNjI0MDIyMn0.SflKxwRJSMeKK924qB_-----"

# Broker configuration
broker_address = "mqtt.example.com"
broker_port = 8883 # Typically TLS/SSL port

# Using the token as username, and an empty string as password (or a placeholder if required)
# The broker's auth plugin will validate the token in the username field.
client.username_pw_set(username=access_token, password="")
client.tls_set() # Assuming TLS is used for secure transport

client.connect(broker_address, broker_port, 60)
client.loop_forever()

The MQTT broker, upon receiving the connection request, will intercept the authentication. It won’t just check a static username/password. Instead, it will forward the provided token (in this case, in the username field) to the configured authorization server for validation. If the token is valid and grants permission to connect, the broker allows the connection.

This pattern effectively decouples authentication from the MQTT broker itself. The broker becomes a relying party, trusting the authorization server to issue valid credentials. This is crucial for managing credentials at scale, as only the authorization server needs to handle the complexities of user/device identity and token issuance. The lifespan of these access tokens is typically short (minutes to hours), mitigating the risk if a token is compromised. Devices are responsible for refreshing their tokens before they expire, usually by re-authenticating with the authorization server.

A common implementation detail is using the clientid in MQTT as a way to map the incoming connection to a specific client application or device identity within the OAuth2 provider. This allows the authorization server to issue tokens that are scoped to that specific clientid, ensuring that a token issued for one device cannot be used by another. The clientid itself might be a UUID, a serial number, or a more descriptive identifier that the authorization server recognizes.

The actual mechanism for passing the token to the MQTT broker can vary. While using the username field is common, some brokers or authentication plugins might support custom headers or a dedicated OAuth2 authentication mechanism that expects the token in a specific format. The key is that the broker’s authentication layer is configured to understand how to extract and validate this token against the authorization server.

The next step in securing your MQTT deployment might involve implementing fine-grained authorization, where tokens not only authenticate a device but also define what topics it can publish or subscribe to.

Want structured learning?

Take the full Mqtt course →