Token Exchange API
Your backend calls this endpoint to exchange an HMAC-signed request for a short-lived DropOnAir JWT. Never call this from client-side code, it requires your Server Secret Key.
POST
https://sdk.droponair.com/api/token/exchangeRequired headers
X-DropOnAir-Key: YOUR_APP_ID
X-DropOnAir-Timestamp: 1708361234 // Unix seconds, ±5 min of server time
X-DropOnAir-Nonce: a7f3k9mzq1r8t2xw // Random ≥16 chars, single-use
X-DropOnAir-Signature: BASE64_HMAC_SHA256 // See signing formula below
Content-Type: application/jsonHMAC signing formula
// message = appId + timestamp + nonce + sha256Hex(requestBodyBytes)
// signature = base64( HMAC-SHA256(serverSecretKey, message) )
import { createHmac, createHash } from 'crypto';
function buildSignature(secret: string, appId: string, timestamp: string, nonce: string, bodyBytes: Buffer): string {
const bodyHash = createHash('sha256').update(bodyBytes).digest('hex');
const message = appId + timestamp + nonce + bodyHash;
return createHmac('sha256', secret).update(message).digest('base64');
}Request body
{
"customerUserToken": "alice-user-id-123" // Stable user identifier
}Response
{
"accessToken": "eyJhbGci...", // Short-lived JWT (15 min)
"expiresIn": 900 // Seconds until expiry
}Full backend example (Node.js)
app.post('/api/droponair/token', async (req, res) => {
const userId = req.auth.userId;
const timestamp = String(Math.floor(Date.now() / 1000));
const nonce = crypto.randomBytes(16).toString('hex');
const body = JSON.stringify({ customerUserToken: userId });
const bodyBytes = Buffer.from(body, 'utf8');
const sig = buildSignature(process.env.DROPONAIR_SERVER_SECRET, process.env.DROPONAIR_APP_ID, timestamp, nonce, bodyBytes);
const result = await fetch('https://sdk.droponair.com/api/token/exchange', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-DropOnAir-Key': process.env.DROPONAIR_APP_ID,
'X-DropOnAir-Timestamp': timestamp,
'X-DropOnAir-Nonce': nonce,
'X-DropOnAir-Signature': sig,
},
body,
});
const { accessToken, expiresIn } = await result.json();
res.json({ accessToken, expiresIn });
});