Skip to content

JWT Authentication

JWT authentication is a token-based authorization mechanism that does not rely on the server retaining client authentication or session information. With the possession of keys, authentication information can be issued in bulk, making it the most straightforward method of authentication.

Note

JWT authentication is not supported in EMQX Serverless deployments.

How JWT Authentication Works

Clients carry the JWT in either the username or password fields (depending on the module configuration) when initiating a connection. EMQX Platform uses the key or certificate configured to decrypt the JWT. If the decryption is successful, authentication is considered successful; otherwise, it fails.

If the signature verification is successful, the JWT authenticator proceeds to check the claims. The JWT authenticator actively checks the validity of the JWT based on these claims, such as iat (Issued At), nbf (Not Before), and exp (Expiration Time). Additional custom claims can also be specified for verification. The client is granted access only if both the signature and claims verifications are successful.

With the default configuration, once JWT authentication is enabled, connections can be made using any username and the following password, which verifies against the default key field emqxsecret:

bash
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJFTVFYIENsb3VkIiwiaWF0IjoxNTE2MjM5MDIyfQ.-k9Ggc6L_Jxq4uUf9xwdJpwRrS3PquL-JZKtAJoOvBo

The JWT Token provided above is for testing purposes only. You can generate a JWT token tailored to your business needs using appropriate tools. See How to Generate JWT for details.

How to Generate JWT

This section provides step-by-step instructions to generate a valid JWT for authenticating clients in EMQX.

Prerequisites

  • A secret key (for HMAC algorithms) or a private key (for RSA/ECDSA)
  • A JWT generation tool or code library (e.g., jwt.io, jjwt, mkjwk, Python, Node.js)
  • Know which algorithm EMQX expects (HS256, RS256, etc.)

JWT Structure

A JWT is composed of three parts:

JWT = base64UrlEncode(Header) + "." + base64UrlEncode(Payload) + "." + Signature
  • Header specifies metadata about the token, such as the algorithm and token type, e.g.:

    json
    {
      "alg": "HS256",
      "typ": "JWT"
    }
  • Payload contains claims (info about the user) like username, exp, or client_attrs, e.g.:

    json
    {
      "username": "emqx_user",
      "exp": 1719830400,
      "client_attrs": {
        "role": "admin",
        "sn": "device-001"
      }
    }
  • Signature validates that the token has not been tampered with, generated by signing the header and payload using the secret or private key.

Steps

  1. Define the JWT Header. For example (for HMAC SHA-256):

    json
    {
      "alg": "HS256",
      "typ": "JWT"
    }

    For RSA/ECDSA, replace "alg" with RS256, ES256, etc., depending on your key type.

  2. Define the JWT Payload. The payload contains claims used by EMQX. Common fields include:

    json
    {
      "sub": "mqtt_client",       // Subject: optional, used for identification
      "username": "emqx_user",    // Optional: used if bound in EMQX config
      "clientid": "client_123",   // Optional: used for client restrictions
      "exp": 1719830400           // Required: expiration time (Unix timestamp)
    }

    Important:

    • exp is required. Without it, EMQX may reject the token.
    • username and clientid can be added if EMQX is configured to verify them in the token.
    • You may also include custom claims like acl or client_attrs.
  3. Base64Url encode the Header and Payload. You can do this manually or use a JWT library.

  4. Sign the JWT. Use your secret or private key to generate the signature:

    • For HMAC (e.g., HS256): HMACSHA256(base64Url(header) + "." + base64Url(payload), secret)
    • For RSA/ECDSA (e.g., RS256): Use a private key with the appropriate signing algorithm.
  5. Assemble the JWT. Concatenate the encoded header, payload, and signature with periods:

    <header>.<payload>.<signature>
  6. Verify the JWT (optional but recommended). Use jwt.io or your development tools to decode and validate the token before use.

Example Using Python (pyjwt)

import jwt
import datetime

secret = "your_shared_secret"

payload = {
    "username": "emqx_user",
    "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1)
}

token = jwt.encode(payload, secret, algorithm="HS256")
print(token)

For RS256, replace secret with your private key and provide the RS256 algorithm.

Result

You now have a signed JWT token that can be used in the MQTT CONNECT packet, either in the username or password field, based on your EMQX configuration.

For detailed instructions on generating a JWT token for complex business use cases, refer to the blog post JWT Authentication and JWKS Endpoint in MQTT: Principle and a Hands-on Guide.

Access Control List (Optional)

The Access Control List (ACL) is an optional extension of an authentication result to control the client's permissions after login. The JWT can include an acl field to specify the client's permissions.

See Access Control List (ACL) for more information.

Client Attributes

Starting from EMQX v5.7.0, you can use the optional client_attrs field in the JWT Payload to set client attributes. Please note that both the keys and values must be of string type.

Example:

json
{
  "exp": 1654254601,
  "username": "emqx_u",
  "client_attrs": {
      "role": "admin",
      "sn": "10c61f1a1f47"
  }
}

Configure JWT Authentication

In the deployment, click Access Control - Extended Authentication, then click JWT Configure Authentication to create a new authentication.

You can complete the related configurations as follows:

When choosing JWT as the Authentication Method:

  • JWT From: Specify the location of the JWT in the client connection request; options: password, username (corresponding to the Password and Username fields in the MQTT client CONNECT packet, respectively)
  • Algorithm: Specify the JWT encryption method, options: hmac-based, public-key;
    • If selecting hmac-based, i.e., JWT uses a symmetric key for generating and verifying signatures (supports HS256, HS384, and HS512 algorithms), you should also configure:
      • Secret: The key used to verify the signature, the same key used for generating the signature.
      • Secret Base64 Encode: Configure whether EMQX needs to decode the Secret using Base64 before verifying the signature; options: True, False, default: False.
    • If selecting public-key, i.e., JWT uses a private key for generating signatures, and a public key is needed for verification (supports RS256, RS384, RS512, ES256, ES384, and ES512 algorithms), you should also configure:
      • Public Key: Specify the PEM-formatted public key used for verifying the signature.
  • Disconnect After Expiration: Configures whether to disconnect clients after their JWT expires, enabled by default.
  • Payload: Add custom Claims checks; users need to add keys and corresponding values to Claim and Expected Value, respectively, supporting ${clientid} and ${username} placeholders. Keys are used to find the corresponding Claim in the JWT, and values are used to compare with the actual value of the Claim.

If selecting JWTS as the authentication method:

In addition to the above configurations, you should also configure:

  • JWKS Endpoint: Specify the server endpoint address for EMQX to query JWKS. The endpoint should support GET requests and return a JWKS that conforms to standards.
  • JWKS Refresh Interval: Specify the refresh interval for JWKS, i.e., the interval at which EMQX queries JWKS. Default value: 300 seconds (s). Click Create to complete the related configurations.
  • Headers: Specify any additional HTTP headers that must be included in the requests to the JWKS server. Adding these HTTP headers ensures that the requests to the JWKS server are properly formatted according to your server's requirements. This configuration allows users to add key-value pairs, for example:
    • Key: Accept
    • Value: application/json

TIP

  • If the current deployment is a dedicated edition, create a VPC Peering Connection, and use the internal network address as the server address.
  • If the current deployment is a BYOC edition, you need to create a VPC Peering Connection in your public cloud console. For details, refer to the section Create BYOC Deployment - VPC Peering Connection Configuration. Use the internal network address as the server address.
  • If you see an "Init resource failure!" message, please check if the server address is correct and if the security group is open.