Authentication

Every request to EdgeMQ requires authentication. This guide explains how to create API keys, choose the right permissions, and authenticate your HTTP and MQTT requests.

Overview

EdgeMQ uses API keys for authentication across both protocols. You create a key in the Console, then use it in one of three ways:

  1. HTTP header — pass the key in the X-API-Key header (simplest for HTTP ingest)
  2. MQTT CONNECT — pass the key in the MQTT password field (for IoT devices)
  3. Token exchange — exchange the key for a short-lived JWT access token (for managing resources via API)

The same API key works for both HTTP and MQTT. You do not need separate keys per protocol.

Step 1: Create an API key

  1. Log in to the EdgeMQ Console
  2. Navigate to API Keys in the sidebar
  3. Click Create API Key
  4. Give it a descriptive name (e.g., production-ingest, ci-deploy, monitoring)
  5. Select the permissions you need (see below)
  6. Click Create Key

The key is shown once — copy it immediately and store it securely. It looks like this:

ing_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345

Step 2: Choose permissions

When creating a key, you select one or more permission scopes:

ScopeWhat it doesUse case
IngestSend data to your endpoints (HTTP and MQTT)Application backends, IoT devices, webhooks
AdminManage endpoints, destinations, views, and keysCI/CD pipelines, infrastructure-as-code, agents
MetricsRead data quality metrics, DLQ files, and delivery statusMonitoring dashboards, alerting

You can combine scopes. For example, a key with Ingest + Metrics can send data and read delivery status.

Principle of least privilege — create separate keys for separate purposes. Your production ingest pipeline should use an ingest-only key. Your CI/CD system should use an admin key. Your monitoring should use a metrics-only key.

Step 3: Authenticate requests

Option A: HTTP header (for HTTP ingest)

Pass your key in the X-API-Key header:

curl -X POST https://your-endpoint.ingest.edge.mq/v1/ingest \
  -H "X-API-Key: ing_live_aBcDeFgH..." \
  -H "Content-Type: application/x-ndjson" \
  -d '{"user_id": "123", "event": "signup", "timestamp": "2026-01-15T10:30:00Z"}'

The ingest node verifies your key and caches the result for fast subsequent requests. No token exchange needed.

Best for: Application backends, webhooks, batch uploads — any HTTP-based producer.

Option B: MQTT CONNECT (for IoT devices)

Pass your key in the MQTT CONNECT packet's password field. The same API key used for HTTP works here — no separate credential needed.

Python (paho-mqtt):

import paho.mqtt.client as mqtt

client = mqtt.Client(transport=class="t-string">"websockets")
client.ws_set_options(path=class="t-string">"/mqtt")
client.username_pw_set(class="t-string">"my-device", class="t-string">"ing_live_aBcDeFgH...")
client.tls_set()
client.connect(class="t-string">"your-endpoint.ingest.edge.mq", class="t-number">443)
client.publish(class="t-string">"sensors/temperature", class="t-string">'{"temp": class="t-number">22.5}')

Node.js (mqtt.js):

import mqtt from class="t-string">'mqtt'

const client = mqtt.connect(class="t-string">'wss:class="t-comment">//your-endpoint.ingest.edge.mq/mqtt', {
  username: class="t-string">'my-device',
  password: class="t-string">'ing_live_aBcDeFgH...'
})
MQTT fieldValuePurpose
passwordYour API keyAuthentication (required)
usernameAny stringDisplay name in metrics (not used for auth)
clientIdDevice identifierConnection tracking; should be unique per device

Authentication happens once at CONNECT time. Subsequent PUBLISH messages on the same connection do not require re-authentication.

Best for: IoT devices, sensors, gateways publishing telemetry via MQTT. See the MQTT guide for full connection setup and additional client library examples.

Option C: Token exchange (for managing resources)

If you need to manage endpoints, destinations, or views via the API, exchange your key for a short-lived JWT:

# Step 1: Exchange your API key for an access token
curl -X POST https://api.edge.mq/v1/token/exchange \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "ing_live_aBcDeFgH...",
    "scope": "admin"
  }'

Response:

{
  "access_token":: "eyJhbGciOiJSUzI1NiI...",
  "token_type":: "Bearer",
  "expires_in":: 900
}
# Step 2: Use the token for API calls
curl https://api.edge.mq/v1/endpoints \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiI..."

The token expires after 15 minutes. Exchange a new one when it expires.

Best for: Managing resources (endpoints, destinations, views), CI/CD automation, agent workflows.

Which method should I use?

ScenarioMethodScope
Send events from my app (HTTP)Direct API keyIngest
Send telemetry from IoT devices (MQTT)MQTT CONNECTIngest
Send events at high volume (HTTP)Token exchangeIngest
Create/update endpoints in CI/CDToken exchangeAdmin
List my endpoints and destinationsToken exchangeAdmin
Create and publish schema viewsToken exchangeAdmin
Monitor delivery statusToken exchangeMetrics
Check DLQ files for failed recordsToken exchangeMetrics
AI agent managing my infrastructureToken exchangeAdmin

Token exchange details

Scope selection

When exchanging a key, you specify which scope to use for the token. The key must have that scope — if you request admin but the key only has ingest, the exchange returns 403 Forbidden.

{
  "api_key":: "ing_live_...",
  "scope":: "admin",
  "ttl":: "15m"
}

The scope parameter accepts: ingest, admin, or metrics. Default is ingest.

The optional ttl parameter controls token lifetime (default 15m). Shorter tokens are more secure.

Token refresh

Tokens are short-lived by design. When your token expires, exchange your API key for a new one. There is no refresh token mechanism — the API key itself is the long-lived credential.

# Your token expired? Just exchange again.
TOKEN=$(curl -s -X POST https://api.edge.mq/v1/token/exchange \
  -H "Content-Type: application/json" \
  -d '{"api_key": "ing_live_...", "scope": "admin"}' \
  | jq -r '.access_token')

Error handling

StatusMeaningAction
401Invalid or revoked API keyCheck the key is correct and not revoked
403Key doesn't have the requested scopeCreate a new key with the right permissions
429Rate limitedWait and retry with exponential backoff

For MQTT, authentication errors are returned as CONNACK return codes:

CONNACK codeMeaningEquivalent HTTP status
0x00Connection accepted200
0x04Bad username or password (invalid API key)401
0x05Not authorized (key lacks Ingest scope)403
0x03Server unavailable (backpressure or capacity)503

All HTTP error responses follow RFC 7807 format with a retry field indicating whether the request can be retried.

Key management

Revoking keys

Revoke a key immediately from the Console. Revocation propagates to all ingest nodes within 30 seconds. Any tokens previously issued from that key continue to work until they expire (max 15 minutes). Active MQTT connections authenticated with the revoked key remain connected until their next re-authentication (e.g., reconnect).

Key rotation

To rotate a key:

  1. Create a new key with the same permissions
  2. Update your applications and devices to use the new key
  3. Revoke the old key once all instances are updated

For MQTT devices, coordinate the key update with device firmware or configuration management before revoking the old key.

Security best practices

  • Store keys in environment variables or a secrets manager — never in source code or device firmware images
  • Use separate keys for separate environments (dev, staging, production)
  • Use separate keys for HTTP and MQTT if you want independent revocation control
  • Use the minimum scope needed for each key
  • Rotate keys periodically (every 90 days recommended)
  • Revoke keys immediately when team members leave or keys are compromised