Seguridad MQTT

Autenticación JWT en MQTT: tokens en el campo de contraseña

Una explicación práctica de cómo transportar JSON Web Tokens en el CONNECT de MQTT, cómo los validan los brokers, cómo gestionar la caducidad y la renovación en los dispositivos y cuándo las credenciales estáticas por dispositivo son la opción más sencilla.

Diagrama de la autenticación JWT en MQTT con un emisor de tokens, un dispositivo y un broker que valida un token firmado
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

La autenticación JWT en MQTT consiste en que el cliente coloca un JSON Web Token firmado en el campo de contraseña de su paquete CONNECT, y el broker valida la firma y los claims en lugar de buscar una contraseña almacenada. Este artículo explica cómo funciona en la red, cómo gestionar la caducidad y la renovación de tokens en dispositivos reales y cuándo merecen la pena esas piezas adicionales frente a las credenciales estáticas por dispositivo.

Cómo viaja un JWT dentro del CONNECT de MQTT

En su autenticación básica, MQTT no tiene un campo dedicado para tokens. Lo que tiene es una cadena de nombre de usuario y un campo de contraseña que la especificación define como datos binarios. Los brokers compatibles con JWT reutilizan ese campo:

CONNECT
  Client ID:  sensor-0042
  Username:   sensor-0042            (a menudo se ignora o se compara con un claim)
  Password:   eyJhbGciOiJSUzI1NiIs...  (el JWT codificado)

Un JWT tiene tres partes codificadas en base64url separadas por puntos: una cabecera que indica el algoritmo, un payload de claims y una firma. Los claims del token típico de un dispositivo tienen este aspecto:

{
  "iss": "https://auth.example.com",
  "sub": "sensor-0042",
  "aud": "mqtt.example.com",
  "iat": 1792130400,
  "exp": 1792134000,
  "topics": {
    "pub": ["plant1/line3/sensor-0042/#"],
    "sub": ["plant1/line3/sensor-0042/cmd/#"]
  }
}

A continuación, el broker, o un plugin de autenticación conectado a él:

  1. Decodifica el token y comprueba la firma con un secreto compartido (HS256) o una clave pública (RS256, ES256).
  2. Comprueba exp, nbf, iss y aud.
  3. Opcionalmente compara sub con el client ID o el nombre de usuario.
  4. Opcionalmente lee claims personalizados para decidir qué topics puede usar el cliente.

Como el token viaja como contraseña, se aplica la misma regla que en cualquier esquema de autenticación MQTT con usuario y contraseña: debe enviarse sobre TLS. Un JWT es una credencial al portador. Quien lo capture puede usarlo hasta que caduque.

Autenticación mejorada de MQTT 5

MQTT 5.0 añade una propiedad Authentication Method y un paquete AUTH para que broker y cliente puedan realizar intercambios de desafío-respuesta y volver a autenticarse durante una sesión activa sin desconectarse. Algunos brokers exponen métodos basados en tokens mediante este mecanismo, lo que permite renovar un token en una conexión abierta. El soporte varía mucho entre brokers y bibliotecas cliente, así que la mayoría de los despliegues siguen usando el enfoque más simple del campo de contraseña y se reconectan para renovar. La especificación OASIS MQTT 5.0 describe el flujo AUTH.

¿Qué brokers admiten JWT?

JWT es una funcionalidad del broker o de un plugin, no forma parte de MQTT en sí. Algunos brokers incluyen un autenticador JWT, y Mosquitto puede validar tokens mediante plugins de autenticación de terceros. Consulta la documentación de tu broker para saber qué algoritmos, fuentes de claves (clave estática o un endpoint JWKS) y mapeos de claims admite.

ConnectMQ no admite autenticación JWT. Un broker de ConnectMQ autentica a los clientes con el nombre de usuario y la contraseña generados en el portal, y vincula cada client ID a sus credenciales emitidas. Los tenants están aislados entre sí, de modo que esas credenciales solo llegan a tu propio broker. Las ventajas e inconvenientes que verás más abajo te ayudarán a decidir si ese modelo o un modelo de tokens se adapta mejor a tu proyecto.

Emitir y usar un token: ejemplo

El siguiente ejemplo muestra las dos mitades de una configuración JWT frente a un broker hipotético en mqtt.example.com que valida tokens RS256. Primero, un servicio emisor mínimo firma un token para un dispositivo:

# pip install pyjwt cryptography
import time
import jwt

PRIVATE_KEY = open("issuer_private.pem", "rb").read()

def issue_device_token(device_id: str, ttl_seconds: int = 3600) -> str:
    now = int(time.time())
    claims = {
        "iss": "https://auth.example.com",
        "sub": device_id,
        "aud": "mqtt.example.com",
        "iat": now,
        "nbf": now - 30,          # tolera un pequeño desfase de reloj
        "exp": now + ttl_seconds,
    }
    return jwt.encode(claims, PRIVATE_KEY, algorithm="RS256")

if __name__ == "__main__":
    print(issue_device_token("sensor-0042"))

Después, el dispositivo se conecta con el token como contraseña y se reconecta con un token nuevo antes de que caduque:

# pip install paho-mqtt requests
import ssl
import time
import requests
import paho.mqtt.client as mqtt

DEVICE_ID = "sensor-0042"
TOKEN_URL = "https://auth.example.com/device-token"
REFRESH_EVERY = 50 * 60   # renueva 10 minutos antes de una caducidad de 60 minutos

def fetch_token() -> str:
    # El dispositivo se autentica ante el emisor con su propio secreto de larga duración
    r = requests.post(TOKEN_URL, json={"device": DEVICE_ID}, timeout=10)
    r.raise_for_status()
    return r.json()["token"]

def on_connect(client, userdata, flags, reason_code, properties):
    print("CONNACK:", reason_code)

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id=DEVICE_ID, protocol=mqtt.MQTTv5)
client.tls_set(cert_reqs=ssl.CERT_REQUIRED)
client.on_connect = on_connect

def connect_with_fresh_token():
    client.username_pw_set(DEVICE_ID, fetch_token())
    client.connect("mqtt.example.com", 8883, keepalive=60)
    client.loop_start()

connect_with_fresh_token()
while True:
    time.sleep(REFRESH_EVERY)
    client.disconnect()      # desconexión limpia, la sesión se mantiene si está configurada
    client.loop_stop()
    connect_with_fresh_token()

Fíjate en el comentario de fetch_token: el dispositivo sigue necesitando algún secreto o certificado de larga duración para identificarse ante el emisor. JWT traslada la credencial estática de la conexión con el broker a la conexión con el emisor; no la elimina.

Patrones de caducidad y renovación

La caducidad es el principal motivo para usar tokens y también la principal fuente de incidentes en producción. Los brokers gestionan un token que caduca de una de estas dos formas:

Comportamiento del broker Efecto en el cliente
Comprueba exp solo en CONNECT La sesión continúa tras la caducidad hasta la siguiente reconexión
Desconecta al cliente en exp El cliente debe reconectarse con un token nuevo antes de ese momento

Patrones que funcionan en dispositivos:

  1. Renueva pronto. Solicita un token nuevo aproximadamente al 80 % de su vida útil, no en el momento de la caducidad.
  2. Reconéctate de forma limpia. Usa una sesión persistente (Clean Start a false con una caducidad de sesión) para que las suscripciones y los mensajes QoS 1 en cola sobrevivan a la reconexión.
  3. Mantén el reloj en hora. Un dispositivo con el reloj desajustado generará o rechazará tokens de forma incorrecta. Sincroniza la hora con NTP antes de solicitar un token y permite un pequeño desfase con nbf.
  4. Gestiona las caídas del emisor. Si el emisor no está disponible, el dispositivo mantiene su conexión actual y reintenta con backoff; no debe cortar una sesión que funciona.
  5. Registra los motivos del CONNACK. Un token caducado o no válido suele producir 0x86 (Bad User Name or Password) o 0x87 (Not authorized) en MQTT 5.

Errores de seguridad con tokens

Los tokens fallan de maneras en que las contraseñas no lo hacen, así que revisa estos puntos antes de pasar a producción:

  • Confusión de algoritmos. Configura el broker para que acepte solo el algoritmo que emites, por ejemplo RS256. Nunca aceptes none y nunca dejes que la cabecera del token elija entre verificación simétrica y asimétrica.
  • Secretos HMAC compartidos en los dispositivos. Si los dispositivos pudieran firmar sus propios tokens HS256, todos tendrían el secreto maestro. Firma los tokens solo en el lado del servidor.
  • Vidas útiles demasiado largas. Un token válido durante un año no es más que una contraseña con pasos adicionales. Mantén vidas útiles lo bastante cortas para que un token filtrado caduque pronto, y lo bastante largas para que los dispositivos con redes deficientes no estén renovando constantemente.
  • Falta de comprobación de audiencia. Sin aud, un token emitido para otro servicio puede reutilizarse contra tu broker.
  • Registrar tokens en logs. Los tokens acaban en logs de depuración e informes de fallos igual que las contraseñas. Registra sub y exp, nunca el token.

JWT frente a credenciales estáticas por dispositivo

Factor JWT Credenciales estáticas por dispositivo
Vida de un secreto robado en la red Hasta la caducidad del token Hasta que se rota la credencial
Infraestructura adicional Emisor de tokens, gestión de claves, sincronización de reloj Ninguna aparte del broker
Revocación Esperar a la caducidad o mantener una lista de denegación Revocar la credencial
Datos de autorización Puede llevar claims de topics en el token Se gestionan en el lado del broker
Complejidad en el dispositivo Cliente HTTP, lógica de renovación de tokens, NTP Guardar una contraseña
Depuración Decodificar el token, comprobar claims y relojes Comprobar usuario y contraseña

JWT destaca cuando ya utilizas un proveedor de identidad, cuando usuarios (no solo dispositivos) se conectan desde navegadores o apps móviles con sesiones cortas, o cuando quieres que la autorización vaya incluida en la propia credencial.

Las credenciales estáticas por dispositivo destacan en flotas de dispositivos donde importa la sencillez: microcontroladores con recursos limitados, emplazamientos con acceso poco fiable a un emisor (una faena minera remota o un campo agrícola con conectividad celular intermitente) y equipos que no quieren operar un servicio de autenticación. Su punto débil, los secretos de larga duración, se resuelve con almacenamiento protegido y rotación planificada. Consulta cómo rotar credenciales MQTT y las notas de diseño de conceptos de ACL en MQTT para la parte de autorización.

Un término medio con un broker MQTT gestionado

Si lo que buscas en JWT es sobre todo "ningún secreto compartido y una forma rápida de cortar el acceso a un dispositivo", puedes conseguir casi todo eso sin tokens: da a cada dispositivo su propio conjunto de credenciales, vincúlalo a un client ID, guárdalo en almacenamiento protegido y rótalo de forma programada. Ese es el modelo que un broker MQTT gestionado como ConnectMQ ofrece de serie, con TLS en 8883 y 8084, bloqueo de IP tras inicios de sesión fallidos repetidos y aislamiento de tenants. En aplicaciones de navegador, mantén las credenciales del broker en tu backend y deja que los usuarios se autentiquen en tu backend con el sistema de tokens que ya utilices.

Empieza con ConnectMQ

¿Quieres una autenticación sólida por dispositivo sin operar un emisor de tokens? Crea un broker MQTT en la nube Serverless gratuito en app.connectmq.com, sin tarjeta de crédito, y conecta tu primer dispositivo sobre TLS con credenciales generadas en minutos.

Preguntas frecuentes

¿ConnectMQ admite autenticación JWT en MQTT?

No. ConnectMQ autentica a los clientes con nombres de usuario y contraseñas generados, con cada client ID vinculado a sus credenciales emitidas. Los tenants están aislados entre sí.

¿Dónde va el JWT en una conexión MQTT?

La mayoría de los brokers lo esperan en el campo de contraseña de CONNECT, a veces con el nombre de usuario igual al ID del dispositivo o a un valor fijo. Algunos brokers MQTT 5 también aceptan tokens mediante autenticación mejorada.

¿Qué ocurre cuando el token caduca durante una sesión?

Depende del broker. Algunos solo validan en el momento de la conexión y otros desconectan al cliente al caducar, así que los dispositivos deben renovar y reconectarse antes de que el token caduque.

¿Es JWT más seguro que una contraseña?

Un token de corta duración limita cuánto tiempo funciona una credencial robada, pero los dispositivos siguen necesitando un secreto de larga duración para obtener tokens. La seguridad global depende de cómo se almacenen y transporten ambos secretos.

Artículos relacionados

Cómo rotar credenciales MQTT sin tiempo de inactividad

Una estrategia de doble credencial paso a paso para rotar usuarios y contraseñas MQTT en toda una flota: prepara la nueva credencial, cambia con respaldo, verifica y solo entonces revoca la antigua.

8 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.