In our IoT Accelerator REST API, enterprise customers authenticate by requesting a JSON Web Token (JWT) from the /iot/api/auth endpoint. This token grants them access to subsequent API calls. However, we have observed that some clients call the authentication endpoint before every request, which is unnecessary and can create performance bottlenecks and may contribute towards unnecessary consumption of rate-limited requests.
This guide explores how to use the token's expiration information to determine when a token is still valid, and when you actually need to request a new one — improving efficiency and reducing authentication load.
Tip: If you are also looking to optimize how you stay within API usage limits, see our Best Practices for Avoiding Rate Limiting in API Requests article.
How JWT Authentication Works
- Your client authenticates once by calling
POST /iot/api/authwith valid credentials. - The API responds with a JWT string, typically in the
access_tokenfield of the JSON response. - The token contains claims (metadata), including an
expfield indicating the expiry time in epoch seconds. - You include this token in the
Authorization: Bearer <token>header of subsequent API requests until it expires.
Understanding the exp Claim
JWTs are composed of three base64-encoded parts: header, payload, and signature. The payload contains standard claims, including exp — the UNIX timestamp (in seconds) when the token expires.
Below is an anonymized example showing the structure you can expect in a token payload:
{
"sub": "user@example.com",
"iss": "https://auth.example.com",
"last_name": "Doe",
"groups": [
"api_read",
"api_write",
"subscription_admin"
],
"organization_ids": {
"default": {
"include": [
"123",
"123.*"
]
}
},
"aud": "api-client",
"upn": "user@example.com",
"azp": "user@example.com",
"enterprise_group_ids": {
"default": {
"include": [
"123",
"123.*"
]
}
},
"exp": 1758908748,
"billing_organization_id": "123",
"iat": 1758906948,
"first_name": "John",
"jti": "uuid-here-1234",
"email": "user@example.com"
}By checking the current time against exp, you can determine whether the token is still valid and avoid unnecessary authentication requests.
Best Practices for JWT Token Management
- Authenticate Once and Reuse the Token: Store the token securely in memory or a secure cache, and reuse it until it expires.
-
Check Expiry Before Each API Call: Compare the current timestamp to the token's
expvalue. - Refresh Proactively: Renew the token shortly before expiry (e.g., 1-2 minutes earlier) to avoid race conditions and failed requests.
-
Handle Expired Tokens Gracefully: If an API request fails with HTTP
401 Unauthorizeddue to token expiry, immediately request a new token and retry the call.
Example: Decoding and Using exp in Python
This example uses the pyjwt package to decode the JWT without verifying the signature (since you only need the claim values).
import time
import requests
import jwt # pip install pyjwt
AUTH_URL = 'https://iot-api.aeris.com/iot/api/auth'
API_URL = 'https://iot-api.aeris.com/iot/api/data'
USERNAME = 'your_username'
PASSWORD = 'your_password'
token_data = None
def get_token():
global token_data
resp = requests.post(AUTH_URL, json={'username': USERNAME, 'password': PASSWORD})
resp.raise_for_status()
token = resp.json()['access_token']
payload = jwt.decode(token, options={"verify_signature": False})
token_data = {
'token': token,
'exp': payload['exp']
}
print(f"New token acquired, expires at {time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(token_data['exp']))}")
def ensure_token():
global token_data
now = int(time.time())
if not token_data or token_data['exp'] - now <120: 2="2" no="No" token="ensure_token()" or="or" expires="expires" in="in" under="under" minutes="minutes" return="return" def="def" headers="headers)" authorization="Authorization" f="f" bearer="Bearer" resp="requests.get(API_URL," if="if" __name__="=" __main__="__main__">
Example: Decoding and Using exp in JavaScript
This example uses the jwt-decode library to inspect the token and check expiry.
const axios = require('axios');
const jwt_decode = require('jwt-decode'); // npm install jwt-decode
const AUTH_URL = 'https://iot-api.aeris.com/iot/api/auth';
const API_URL = 'https://iot-api.aeris.com/iot/api/data';
const USERNAME = 'your_username';
const PASSWORD = 'your_password';
let tokenData = null;
async function getToken() {
const resp = await axios.post(AUTH_URL, { username: USERNAME, password: PASSWORD });
const token = resp.data.access_token;
const payload = jwt_decode(token);
tokenData = {
token,
exp: payload.exp
};
console.log(`New token acquired, expires at ${new Date(tokenData.exp * 1000).toISOString()}`);
}
async function ensureToken() {
const now = Math.floor(Date.now() / 1000);
if (!tokenData || tokenData.exp - now <120) await="await" return="return" async="async" function="function" const="const" token="await" resp="await">
Conclusion
Instead of calling /iot/api/auth before every request, read the exp claim of your JWT token to determine if it's still valid. By checking and reusing your token until it is near expiry, you reduce unnecessary network calls, improve performance, and minimize authentication load on the server.
Implementing token caching and proactive renewal is a best practice that will make your integration with the IoT Accelerator REST API more efficient and responsive.
This approach also complements our guidance on avoiding rate limiting. See our Best Practices for Avoiding Rate Limiting in API Requests for strategies that work alongside token optimization.
0 Comments