Authentication
How an MQTT client authenticates to KubeMQ — password-as-JWT in the CONNECT packet, ClientID as identity, ACL authorization, and the open no-auth default.
This guide explains how a native MQTT client proves who it is to the KubeMQ MQTT connector and
what it may do once connected. MQTT carries the credential in the standard Password field of
the CONNECT packet — there is no MQTT-specific auth flag — so any off-the-shelf MQTT 3.1.1 / 5.0
client authenticates by setting username/password the way it already does.
On a stock dev broker, authentication is off — every CONNECT succeeds, the Password field is
ignored, and ACL checks are skipped. So the examples clone-and-run with no credentials. To turn
auth on, configure an auth provider at the server level (there is no MQTT-specific auth env
var); see Auth & security.
Password-as-JWT
The connector uses password-as-JWT authentication. The MQTT Password field carries a KubeMQ
JWT; the Username field is accepted but is display-only — it is stored for the connections
endpoint and never checked against the token.
| MQTT CONNECT field | Role | Notes |
|---|---|---|
Password | The credential — a KubeMQ JWT | Must be set when auth is on; the MQTT spec requires PasswordFlag=true when a password is present |
Username | Display / audit label | Surfaced on the connections endpoint; never validated against the token |
ClientID | The identity | Becomes the KubeMQ ClientID; used for ACL checks and the $reply/<clientID>/... reply namespace |
A CONNECT therefore looks like this — the JWT goes in the password slot, not the username:
CONNECT
ClientID: my-client ← the identity
Username: alice ← display label only
Password: <KubeMQ JWT> ← the actual credential
PasswordFlag: trueAuthentication is checked once, at CONNECT time only. There is no mid-connection token recheck — revoking a token does not disconnect an already-authenticated session.
Connecting with a JWT
Put the JWT in the password slot; the username is cosmetic. The same code works against an auth-disabled broker (the server simply does not validate the token).
// paho.mqtt.golang (MQTT 3.1.1) — username is display-only, password is the KubeMQ JWT.
opts := mqtt.NewClientOptions().
AddBroker("tcp://broker:1883").
SetClientID("my-client").
SetUsername("alice"). // display-only
SetPassword(os.Getenv("KUBEMQ_MQTT_JWT")) // KubeMQ JWT token
client := mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
log.Fatalf("connect (bad/expired JWT? auth-enabled broker?): %v", token.Error())
}# paho-mqtt (MQTT 5.0) — username is display-only, password is the KubeMQ JWT.
import os
import paho.mqtt.client as mqtt
from paho.mqtt.enums import CallbackAPIVersion
client = mqtt.Client(
callback_api_version=CallbackAPIVersion.VERSION2,
client_id="my-client",
protocol=mqtt.MQTTv5,
)
client.username_pw_set("alice", os.environ["KUBEMQ_MQTT_JWT"]) # (display, JWT)
client.connect("broker", 1883, keepalive=30)// mqtt.js (MQTT 5.0) — username is display-only, password is the KubeMQ JWT.
import * as mqtt from "mqtt";
const client = mqtt.connect("tcp://broker:1883", {
protocolVersion: 5,
clientId: "my-client",
username: "alice", // display-only
password: process.env.KUBEMQ_MQTT_JWT, // KubeMQ JWT token
clean: true,
});CONNACK reason codes
What the broker returns at CONNECT time depends on whether auth is enabled and whether the JWT is valid:
| Scenario | Packet | Reason code |
|---|---|---|
| Auth disabled — any password accepted | CONNACK | 0x00 success |
| Auth enabled — valid JWT | CONNACK | 0x00 success |
Auth enabled — empty password (or PasswordFlag=false) | CONNACK | 0x86 bad username/password |
| Auth enabled — invalid JWT or bad signature | CONNACK | 0x86 bad username/password |
When auth is enabled, a CONNECT with an empty Password is refused immediately with 0x86; the
connection is never established. Clients must always supply the token in the Password field.
ACL authorization
Once connected, every publish and subscribe is checked against the KubeMQ ACL. Rules are
evaluated per (pattern, channel, read/write) tuple, against the identity derived from the
ClientID.
| Outcome | Packet | Reason code |
|---|---|---|
| Allowed (publish) | PUBACK | 0x00 |
| Allowed (subscribe) | SUBACK | 0x01 (granted QoS) |
| Denied on publish | PUBACK | 0x87 not authorized |
| Denied on subscribe | SUBACK | 0x87 not authorized |
Two namespace rules sit alongside the ACL:
$reply/<clientID>/<suffix>— a client's own reply namespace is always allowed, regardless of ACL rules. This is the local topic an RPC requester subscribes to for responses; see Topic mapping.- Other
$-prefixed topics (except$share/) are denied by default.
Authorization is checked at CONNECT for the password, then at each publish/subscribe for the
ACL — but never again on an open subscription. A denied publish returns PUBACK 0x87; treat it
as a permission error, not a transient failure to retry.
Open (no-auth) default
When no auth provider is configured the broker is open: the Password field is ignored, every
CONNECT succeeds, and ACL checks are skipped. This matches KubeMQ's gRPC and REST parity behaviour
and is the mode every example in the docs assumes.
To enable authentication, configure the KubeMQ server with an auth provider (the shared server-level auth block) — no MQTT-specific environment variable controls auth. Because it is a shared setting, the same JWT model applies across all KubeMQ connectors; see Auth & security.
Quick decision guide
| You want… | Do this |
|---|---|
| Clone-and-run on a stock dev broker | Connect with no credentials (auth is off) |
| Authenticate with a KubeMQ identity | Put the JWT in the Password field; Username is cosmetic |
| Set a stable identity for ACL / RPC replies | Set a meaningful ClientID — it is the identity, not the username |
| Diagnose a rejected CONNECT | Look for CONNACK 0x86 (bad/empty JWT) |
| Diagnose a rejected publish/subscribe | Look for PUBACK / SUBACK 0x87 (ACL deny) |
Related
TLS and WebSocket
Encrypt the credential in transit — tls:// on 8883 and ws:// on 8083, both carrying the same password-as-JWT CONNECT.
Auth & security
The shared JWT model, ACL, and TLS/security concepts across KubeMQ connectors.
Topic mapping
The per-client $reply reply namespace and the prefix grammar the ACL is checked against.
Was this page helpful?
Getting Started
Connect a stock MQTT client to KubeMQ and run a publish-and-subscribe round-trip over the Events pattern in minutes — no KubeMQ SDK required.
Commands
RPC with execution acknowledgement over MQTT 5.0 — the commands/ prefix, $reply response topics, correlation data, and the kubemq-executed pass/fail signal.