Overview
JSON Web Tokens (JWT) provide a stateless, sessionless way to authenticate with the Mango by Radix IoT REST API. Unlike session-based authentication, which requires a login call and XSRF token management, JWT tokens are self-contained credentials that you include in every request as a Bearer token. This makes them ideal for automated scripts, scheduled cron jobs, service-to-service communication, and any integration where managing browser-like sessions is impractical. JWT token-based authentication has been available since Mango 3.3.0. This guide covers how to generate tokens, use them in API requests, manage expiration, and follow security best practices.
Two behaviours shape every design decision in this guide, so read them before you issue your first token:
- A token represents a user, and resolves that user’s current permissions. When a request arrives, Mango reads the username from the token, loads that user, and authenticates as them with whatever roles the user has right now. The token does not carry a frozen copy of a permission set, and it does not carry the permissions of whoever created it. An admin can create a token on behalf of another user; the resulting token still acts as that other user. Change the user’s roles and every token for that user immediately reflects the change.
- Revocation is per user, not per token. Mango stores a token version number on the user record and embeds it in each token. Revoking increments that number, which invalidates every token that user holds at once. There is no per-token identifier, no per-token revoke, and no token list to delete a single entry from.
Warning
Because revocation is user-wide, issuing several tokens to one Mango user does not give you independent revocation. If one integration is compromised and you revoke, every other integration authenticating as that same user breaks at the same moment. When integrations must be revocable independently, give each one its own dedicated least-privilege Mango user.
Prerequisites
- Mango 4.x or 5.x (JWT support available since Mango 3.3.0)
- Admin access to create tokens, or a user account creating a token for itself
- HTTPS configured on the Mango server — a bearer token is a credential and should never cross the network in plaintext
- A client application, script, or tool that will make REST API calls (e.g., Python, curl, Postman, Node.js)
- Basic understanding of HTTP headers and REST API concepts
Step 1: Generate a JWT Token via the UI
The most direct way to create a token is through the Mango user interface. Token management lives on the user record: open the user you want the token to represent, either from Access management > Users as an admin, or from your own user page when creating a token for yourself.
- Log in to Mango as an admin (or as the user who needs the token)
- Open the user account that the token will represent
- On that user’s page, find the authentication token controls: Expiry preset, Expiry date, an Authentication token box, and three buttons
- Choose an Expiry preset, or set an Expiry date directly with the date picker. Setting a date clears the preset, and vice versa. The presets are the only fixed choices offered:
| Expiry preset | Fits |
|---|---|
| 1 day (the default) | Manual testing, debugging, one-off scripts |
| 1 week · 2 weeks | Short-lived work, a data migration window |
| 1 month · 3 months · 6 months | Recurring automation and cron jobs |
| 1 year · 2 years · 5 years · 10 years | Long-running service integrations, paired with a rotation schedule |
Anything not in that list — an hour, 30 days, 90 days — has to be set as an Expiry date rather than picked as a preset.
- Click Create auth token
- The token appears in the Authentication token box. Copy it with the Copy to clipboard button beside it
Warning
Mango has no “never expires” option. The UI cannot leave the expiry blank — it arrives pre-set to 1 day — but the REST API can, and a create call that omits the expiry gets a token lasting five minutes. That is long enough to look like it worked while you were testing and short enough to break the integration the same day. Set it explicitly in Step 2.
Danger
The full token value is only displayed once at creation time. If you lose it, you cannot recover it — you must generate a replacement. Store it securely and treat it like a password.
Note
The token authenticates as the user it represents and receives that user’s permissions as they stand at the time of each request. If that user has admin access, so does the token; if you later remove a role from the user, the token loses that access immediately without being reissued. Create tokens under a dedicated user account carrying the minimum permissions your integration needs.
Step 2: Generate a Token via the REST API
You can also create tokens programmatically, which is useful for bootstrapping automated deployments.
Token creation is deliberately restricted. Mango only issues a token when the caller authenticated with a username and password – basic auth, or a session login. You cannot bootstrap fresh long-lived tokens from an existing token: that path is turned off by authentication.mango-jwt.allowTokenCreation=false in mango.properties, and even when it is switched on, the new token’s expiry is capped at the remaining lifetime of the token that requested it. A caller may create a token for itself; creating one for a different user requires admin.
Warning
Every example below uses https and placeholder credentials on purpose. Sending a login or a bearer token over plain HTTP exposes the credential to anyone on the path, and the default admin password should be changed before a server is reachable at all.
Using curl
# Supply credentials from the environment rather than the command line
: "${MANGO_URL:?e.g. https://mango.example.com}"
: "${MANGO_USER:?service account username}"
: "${MANGO_PASSWORD:?service account password}"
# Create a JWT token with an explicit expiry. Authenticate this call with
# basic auth (enabled by default: authentication.basic.enabled=true). Basic
# auth counts as a username-and-password login, and a request that carries an
# Authorization header needs no session, cookie or XSRF token. (Logging in
# with a session first does not work here as written: login issues a new
# XSRF-TOKEN cookie, so a header holding the old value gets 403.)
# The path is /auth-tokens/create and the field is "expiry" - a POST to
# /auth-tokens with "expiryDate" creates nothing. Add "username" to create
# a token for someone else (admin only); omit it to create one for yourself.
curl -X POST "$MANGO_URL/rest/latest/auth-tokens/create" \
-u "$MANGO_USER:$MANGO_PASSWORD" \
-H "Content-Type: application/json" \
-d '{"expiry": "2027-01-01T00:00:00.000Z"}'
The response includes the token string that you can save for future use.
Using Python
import os
import requests
MANGO_URL = os.environ["MANGO_URL"] # e.g. https://mango.example.com
MANGO_USER = os.environ["MANGO_USER"]
MANGO_PASSWORD = os.environ["MANGO_PASSWORD"]
# Create a token with an explicit expiry, authenticating with basic auth.
# Token creation requires a username-and-password login, and basic auth is
# one: there is no login call, cookie or XSRF token to manage.
# Omitting "expiry" does not mean "no expiry" - it means five minutes.
response = requests.post(
f"{MANGO_URL}/rest/latest/auth-tokens/create",
auth=(MANGO_USER, MANGO_PASSWORD),
json={"expiry": "2027-01-01T00:00:00.000Z"}
)
# /create answers 201 Created, not 200
if response.status_code == 201:
token_data = response.json()
print(f"Token: {token_data['token']}")
else:
print(f"Error: {response.status_code} {response.text}")
Note
The auth-token endpoints, verified against Mango 5.7.4, are all POSTs under /rest/latest/auth-tokens: /create (body username and expiry; username may be omitted to mean yourself), /revoke and /revoke/{username}, and /reset-keys. There are also GET /public-key and GET /verify. Note that /create answers 201 Created, not 200.
Step 3: Use the JWT Token in API Requests
Once you have a token, include it in the Authorization header of every HTTP request using the Bearer scheme. No login step or XSRF token is needed.
curl Examples
# Get the current user
curl -H "Authorization: Bearer $MANGO_API_TOKEN" \
"https://mango.example.com/rest/latest/users/current"
# Get a point's latest value (the response is a list, newest first)
curl -H "Authorization: Bearer $MANGO_API_TOKEN" \
"https://mango.example.com/rest/latest/point-values/latest/DP_Zone1_Temp"
# Set a point value
curl -X PUT \
-H "Authorization: Bearer $MANGO_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"dataType": "NUMERIC", "value": 72.5}' \
"https://mango.example.com/rest/latest/point-values/DP_Setpoint1"
Python Example
import os
import requests
MANGO_URL = os.environ["MANGO_URL"] # e.g. https://mango.example.com
TOKEN = os.environ["MANGO_API_TOKEN"]
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {TOKEN}",
"Accept": "application/json"
})
# No login step required
response = session.get(
f"{MANGO_URL}/rest/latest/point-values/latest/DP_Zone1_Temp"
)
print(response.json())
Postman
- Open Postman and create a new request
- Go to the Authorization tab
- Select Bearer Token from the Type dropdown
- Paste your JWT token in the Token field
- Send the request — no login or cookie management needed
Step 4: Manage Token Expiration
Check Token Expiry
You can decode a JWT token to inspect its expiration without verifying the signature. JWT tokens consist of three base64-encoded parts separated by dots. The middle part (payload) contains the expiry:
import os
import json
import base64
from datetime import datetime
def decode_jwt_payload(token):
"""Decode the payload of a JWT token (without verification)."""
payload_b64 = token.split(".")[1]
# Add padding if needed
padding = 4 - len(payload_b64) % 4
payload_b64 += "=" * padding
payload = json.loads(base64.b64decode(payload_b64))
exp_time = datetime.fromtimestamp(payload.get("exp", 0))
print(f"Token expires: {exp_time}")
# Mango sets the subject to the username of the represented user, and adds
# two claims of its own: "id" (that user's numeric id) and "v" (the user's
# token version, which is what revocation increments).
print(f"Subject (username): {payload.get('sub')}")
print(f"User id: {payload.get('id')} token version: {payload.get('v')}")
return payload
decode_jwt_payload(os.environ["MANGO_API_TOKEN"])
Revoke Tokens
Revocation in Mango works at two levels, and neither of them targets a single token.
Revoke every token belonging to one user. On that user’s page, click Revoke auth tokens for <username>. Mango increments the token version stored on the user, and because every token carries the version it was signed with, all of that user’s outstanding tokens stop validating at once.
Revoke every token on the system. The Revoke all auth tokens button resets the JWT signing keys: Mango generates a new key pair, which invalidates every token issued under the old keys for every user. The button is only shown to superadmins. This is the response to a suspected key compromise, not a routine operation — it will break every API integration on the instance simultaneously.
Both actions also require that your current session was authenticated with a password rather than with a token. A request authenticated by a JWT cannot revoke anything.
Danger
There is no way to revoke one token and leave that user’s other tokens working. If a single integration’s token leaks and that user also serves three other integrations, revoking takes all four offline. This is the reason to give each integration its own Mango user.
Rotate Tokens
Rotation has to be a clean cutover, because you cannot retire the old token on its own while the new one keeps working:
- Create the replacement token before the current one expires
- Roll it out to every consumer authenticating as that user
- Let the old token lapse at its expiry date, or — if you need it dead immediately and you have confirmed no other consumer of that user is still live — revoke that user’s tokens
- Diarise the next rotation ahead of the new expiry date, so the changeover is planned rather than triggered by a failed integration
Step 5: JWT vs. Session Authentication Comparison
| Feature | JWT Token | Session (Cookie) |
|---|---|---|
| Setup complexity | Simple — one header per request | Requires login call, XSRF token, cookies |
| State management | Stateless — no server-side session | Stateful — server tracks session |
| Best for | Scripts, cron jobs, service integrations | Browser-based apps, interactive use |
| XSRF protection | Not needed | Required (matching header + cookie) |
| Expiration | Set explicitly at creation; defaults to five minutes if omitted | Tied to session timeout |
| Revocation | Per user — revoking invalidates all of that user’s tokens | Session ends on logout or timeout |
| Multi-server | Works across load-balanced instances | May require sticky sessions |
| Security risk | Token leakage grants access until it expires or the user’s tokens are revoked | Session cookie scoped to browser |
Step 6: Security Best Practices
Follow these practices to keep your API tokens secure:
- Use HTTPS — Always use TLS encryption in production. JWT tokens sent over plain HTTP can be intercepted
- Limit permissions — Create tokens for users with the minimum required permissions. Never use admin tokens for read-only integrations
- Set an explicit expiration — Use the shortest practical expiry period, and set it deliberately every time. There is no “never expires” setting; leaving it blank yields a five-minute token
- Store securely — Keep tokens in environment variables or a secrets manager, never in source code or version control
- Rotate regularly — Replace tokens periodically, especially after personnel changes
- Monitor usage — Review the Mango audit log for unexpected API access patterns
- Revoke promptly — If a token may have been compromised, revoke that user’s tokens without delay, accepting that all of that user’s tokens go with it
- One dedicated user per integration — Because revocation is user-wide, isolation comes from separate users, not separate tokens. Give each script or service its own least-privilege Mango user so you can cut one off without touching the others
# Store token in an environment variable (Linux/Mac)
export MANGO_API_TOKEN="paste-your-jwt-here"
# Reference it in scripts
curl -H "Authorization: Bearer $MANGO_API_TOKEN" \
"https://mango.example.com/rest/latest/point-values/latest/DP_Zone1_Temp"
# On Windows (PowerShell)
$env:MANGO_API_TOKEN = "paste-your-jwt-here"
# Use in requests
Invoke-RestMethod -Uri "https://mango.example.com/rest/latest/users/current" `
-Headers @{ Authorization = "Bearer $env:MANGO_API_TOKEN" }
Verification
Confirm your JWT authentication setup is working:
- Token generation succeeds via the UI or API
- API requests with the Bearer header return 200 status codes
- Requests without a token (or with an expired token) return 401 Unauthorized
- The token acts as the user it represents: generate a token for a second, lower-privilege user, confirm access matches that user rather than the admin who created it, then change that user’s roles and confirm the same token’s access changes without reissuing it
- Revocation behaves as documented: issue two tokens for one user, revoke that user’s tokens, and confirm both stop working
- The decoded
subclaim contains the represented user’s username - HTTPS is enabled for production deployments
Troubleshooting
401 Unauthorized with a valid token
- Verify the
Authorizationheader format is exactlyBearer <token>(note the space after Bearer) - Check that the token has not expired — decode the payload to inspect the
expclaim. If it expired suspiciously fast, the creation call probably omitted an expiry and got the five-minute default - Confirm nobody has revoked tokens for the represented user, or reset the JWT signing keys system-wide. Either action invalidates this token even though nothing about the token itself changed
- Confirm the represented user still exists and is enabled
Every integration lost access at the same moment
- This is the signature of user-wide revocation. Someone revoked tokens for a user that several integrations share, or an admin reset the signing keys
- Reissue tokens, then split the integrations onto separate dedicated users so the next revocation is contained
403 Forbidden for specific endpoints
- The user the token represents lacks the required permissions — remember the token carries no permissions of its own, and the creator’s privileges are irrelevant
- Check that user’s roles under Access management > Users
- Some endpoints (e.g., user management, system settings) require admin privileges
Token creation returns an error
- Ensure the expiry date is in the future and uses ISO 8601 format with timezone
- A 403 on the create call after a session login usually means the
X-XSRF-TOKENheader still holds the pre-login value: login issues a newXSRF-TOKENcookie. Authenticate the create call with basic auth instead, as in Step 2 - Confirm the call was authenticated with a username and password. Requests authenticated by an existing JWT cannot mint tokens unless
authentication.mango-jwt.allowTokenCreation=trueis set inmango.properties, and even then the requested expiry cannot exceed the lifetime of the token making the request - Verify you are creating the token for yourself, or that you hold admin to create one on another user’s behalf
- Check that the auth-tokens REST endpoint is available in your Mango version (requires 3.3.0+)
Token works in Postman but not in my script
- Ensure you are not accidentally including extra whitespace or newline characters in the token string
- Some HTTP clients require explicit header encoding — confirm the
Authorizationheader is sent correctly by inspecting the raw request - If using HTTPS with a self-signed certificate, configure your client to trust the certificate or skip verification in development