Skip to main content
Version: 1.0.0

JWT Token Implementation

This guide covers the complete implementation of JWT (JSON Web Token) authentication for RBIH APIs, including token generation, validation, and refresh strategies.

Token Structure​

JWT tokens contain the following claims:

{
"iss": "your_client_id",
"sub": "api_access",
"provider": "provider_code",
"iat": 1642345678,
"exp": 1642367278
}

Claim Descriptions​

  • iss (Issuer): Your RBIH client identifier
  • sub (Subject): Always set to "api_access" for API operations
  • provider: Service provider code (varies by API)
  • iat (Issued At): Token creation timestamp
  • exp (Expiration): Token expiration timestamp

Implementation Examples​

Node.js Implementation​

const jwt = require('jsonwebtoken');
const crypto = require('crypto');

class RBIHAuth {
constructor(clientId, clientSecret) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.tokenCache = new Map();
}

generateToken(providerId, environment = 'sandbox') {
const validity = environment === 'production' ? 12 * 60 * 60 : 6 * 60 * 60;

const payload = {
iss: this.clientId,
sub: 'api_access',
provider: providerId,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + validity
};

const token = jwt.sign(payload, this.clientSecret, {
algorithm: 'HS256',
header: {
typ: 'JWT',
alg: 'HS256'
}
});

// Cache token for reuse
this.cacheToken(providerId, token, payload.exp);

return token;
}

cacheToken(providerId, token, expiry) {
this.tokenCache.set(providerId, {
token,
expiry: expiry * 1000 // Convert to milliseconds
});
}

getValidToken(providerId, environment = 'sandbox') {
const cached = this.tokenCache.get(providerId);

// Check if cached token is still valid (with 5-minute buffer)
if (cached && Date.now() < (cached.expiry - 5 * 60 * 1000)) {
return cached.token;
}

// Generate new token if cache miss or expired
return this.generateToken(providerId, environment);
}

validateToken(token) {
try {
const decoded = jwt.verify(token, this.clientSecret);
return { valid: true, decoded };
} catch (error) {
return { valid: false, error: error.message };
}
}
}

// Usage
const auth = new RBIHAuth('your_client_id', 'your_client_secret');
const token = auth.getValidToken('101', 'sandbox');

Python Implementation​

import jwt
import time
from datetime import datetime, timedelta
from typing import Dict, Optional

class RBIHAuth:
def __init__(self, client_id: str, client_secret: str):
self.client_id = client_id
self.client_secret = client_secret
self.token_cache: Dict[str, Dict] = {}

def generate_token(self, provider_id: str, environment: str = 'sandbox') -> str:
validity_hours = 12 if environment == 'production' else 6

now = int(time.time())
payload = {
'iss': self.client_id,
'sub': 'api_access',
'provider': provider_id,
'iat': now,
'exp': now + (validity_hours * 3600)
}

token = jwt.encode(
payload,
self.client_secret,
algorithm='HS256',
headers={'typ': 'JWT', 'alg': 'HS256'}
)

# Cache token for reuse
self._cache_token(provider_id, token, payload['exp'])

return token

def _cache_token(self, provider_id: str, token: str, expiry: int):
self.token_cache[provider_id] = {
'token': token,
'expiry': expiry * 1000 # Convert to milliseconds
}

def get_valid_token(self, provider_id: str, environment: str = 'sandbox') -> str:
cached = self.token_cache.get(provider_id)

# Check if cached token is still valid (with 5-minute buffer)
if cached and time.time() * 1000 < (cached['expiry'] - 5 * 60 * 1000):
return cached['token']

# Generate new token if cache miss or expired
return self.generate_token(provider_id, environment)

def validate_token(self, token: str) -> Dict:
try:
decoded = jwt.decode(token, self.client_secret, algorithms=['HS256'])
return {'valid': True, 'decoded': decoded}
except jwt.InvalidTokenError as e:
return {'valid': False, 'error': str(e)}

# Usage
auth = RBIHAuth('your_client_id', 'your_client_secret')
token = auth.get_valid_token('101', 'sandbox')

Token Refresh Strategy​

Automatic Token Refresh​

class TokenManager {
constructor(auth, providerId, environment) {
this.auth = auth;
this.providerId = providerId;
this.environment = environment;
this.refreshBuffer = 5 * 60 * 1000; // 5 minutes
}

async getToken() {
const cached = this.auth.tokenCache.get(this.providerId);

if (!cached || this.isTokenExpiringSoon(cached)) {
await this.refreshToken();
}

return this.auth.tokenCache.get(this.providerId).token;
}

isTokenExpiringSoon(cached) {
return Date.now() > (cached.expiry - this.refreshBuffer);
}

async refreshToken() {
console.log(`Refreshing token for provider ${this.providerId}`);
const newToken = this.auth.generateToken(this.providerId, this.environment);

// Notify application of token refresh
this.onTokenRefresh?.(newToken);

return newToken;
}

onTokenRefresh(callback) {
this.onTokenRefresh = callback;
}
}

Environment-Specific Configuration​

Sandbox Configuration​

const sandboxConfig = {
tokenValidity: 6 * 60 * 60, // 6 hours
baseUrl: 'https://sandbox.rbihapis.com',
refreshBuffer: 5 * 60, // 5 minutes
algorithm: 'HS256'
};

Production Configuration​

const productionConfig = {
tokenValidity: 12 * 60 * 60, // 12 hours
baseUrl: 'https://api.rbihapis.com',
refreshBuffer: 30 * 60, // 30 minutes
algorithm: 'HS256'
};

Error Handling​

Common JWT Errors​

function handleJWTError(error) {
switch (error.name) {
case 'TokenExpiredError':
return {
code: 'TOKEN_EXPIRED',
message: 'JWT token has expired',
action: 'Generate new token'
};

case 'JsonWebTokenError':
return {
code: 'INVALID_TOKEN',
message: 'JWT token is malformed',
action: 'Check token generation logic'
};

case 'NotBeforeError':
return {
code: 'TOKEN_NOT_ACTIVE',
message: 'JWT token is not active yet',
action: 'Check system clock synchronization'
};

default:
return {
code: 'JWT_ERROR',
message: 'Unknown JWT error',
action: 'Contact support'
};
}
}

Security Considerations​

Token Storage​

// ✅ Good: Secure token storage
class SecureTokenStorage {
constructor() {
this.tokens = new Map();
}

store(providerId, token) {
// In production, use encrypted storage
this.tokens.set(providerId, this.encrypt(token));
}

retrieve(providerId) {
const encrypted = this.tokens.get(providerId);
return encrypted ? this.decrypt(encrypted) : null;
}

encrypt(data) {
// Implement encryption logic
return data; // Simplified for example
}

decrypt(data) {
// Implement decryption logic
return data; // Simplified for example
}
}

// ❌ Bad: Insecure token storage
localStorage.setItem('jwt_token', token); // Never do this

Clock Synchronization​

// Verify system clock synchronization
async function verifyClockSync() {
try {
const response = await fetch('https://worldtimeapi.org/api/timezone/Etc/UTC');
const { unixtime } = await response.json();
const serverTime = unixtime * 1000;
const localTime = Date.now();
const drift = Math.abs(serverTime - localTime);

if (drift > 60000) { // 1 minute tolerance
console.warn(`Clock drift detected: ${drift}ms`);
return false;
}

return true;
} catch (error) {
console.error('Failed to verify clock sync:', error);
return false;
}
}

Testing JWT Implementation​

Unit Tests​

const assert = require('assert');

describe('JWT Token Generation', () => {
const auth = new RBIHAuth('test_client', 'test_secret');

it('should generate valid JWT token', () => {
const token = auth.generateToken('101', 'sandbox');
const validation = auth.validateToken(token);

assert.strictEqual(validation.valid, true);
assert.strictEqual(validation.decoded.iss, 'test_client');
assert.strictEqual(validation.decoded.provider, '101');
});

it('should cache tokens correctly', () => {
const token1 = auth.getValidToken('101', 'sandbox');
const token2 = auth.getValidToken('101', 'sandbox');

assert.strictEqual(token1, token2);
});

it('should handle expired tokens', () => {
// Mock expired token
const expiredPayload = {
iss: 'test_client',
sub: 'api_access',
provider: '101',
iat: Math.floor(Date.now() / 1000) - 7200,
exp: Math.floor(Date.now() / 1000) - 3600
};

const expiredToken = jwt.sign(expiredPayload, 'test_secret');
const validation = auth.validateToken(expiredToken);

assert.strictEqual(validation.valid, false);
assert(validation.error.includes('expired'));
});
});

This JWT implementation provides a robust foundation for RBIH API authentication with proper caching, automatic refresh, and comprehensive error handling.