Show code
viewof tokenLifetimeMinutes = Inputs.range([5, 120], {
value: 60,
step: 5,
label: "Access token lifetime (minutes)"
})
viewof deviceCount = Inputs.range([100000, 50000000], {
value: 10000000,
step: 100000,
label: "Number of devices"
})
viewof costPer1000Calls = Inputs.range([0.01, 1.00], {
value: 0.10,
step: 0.01,
label: "Cost per 1,000 API calls ($)"
})
viewof refreshTokenDays = Inputs.range([7, 365], {
value: 90,
step: 1,
label: "Refresh token lifetime (days)"
})
refreshesPerDay = (24 * 60) / tokenLifetimeMinutes
totalApiCalls = deviceCount * refreshesPerDay
dailyCost = (totalApiCalls / 1000) * costPer1000Calls
reAuthRate = Math.round(deviceCount / refreshTokenDays)
pollingOverhead = reAuthRate * 12
compromiseWindowReduction = ((60 - tokenLifetimeMinutes) / 60 * 100).toFixed(1)
html`<div style="background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); padding: 1.2rem; border-radius: 8px; border-left: 4px solid #16A085; margin: 1rem 0; font-family: system-ui, sans-serif;">
<h4 style="margin-top: 0; color: #2C3E50;">Token Lifecycle Cost Calculator</h4>
<table style="width: 100%; border-collapse: collapse; font-size: 0.95rem;">
<tr style="border-bottom: 1px solid #dee2e6;">
<td style="padding: 6px 8px; font-weight: 600; color: #2C3E50;">Refreshes per device per day</td>
<td style="padding: 6px 8px; text-align: right; color: #16A085; font-weight: 600;">${refreshesPerDay.toFixed(1)}</td>
</tr>
<tr style="border-bottom: 1px solid #dee2e6;">
<td style="padding: 6px 8px; font-weight: 600; color: #2C3E50;">Total API calls per day</td>
<td style="padding: 6px 8px; text-align: right; color: #16A085; font-weight: 600;">${(totalApiCalls / 1e6).toFixed(1)}M</td>
</tr>
<tr style="border-bottom: 1px solid #dee2e6;">
<td style="padding: 6px 8px; font-weight: 600; color: #2C3E50;">Daily token refresh cost</td>
<td style="padding: 6px 8px; text-align: right; color: #E67E22; font-weight: 700; font-size: 1.1rem;">$${dailyCost.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 0})}/day</td>
</tr>
<tr style="border-bottom: 1px solid #dee2e6;">
<td style="padding: 6px 8px; font-weight: 600; color: #2C3E50;">Re-authentications per day</td>
<td style="padding: 6px 8px; text-align: right; color: #16A085; font-weight: 600;">${reAuthRate.toLocaleString()}</td>
</tr>
<tr style="border-bottom: 1px solid #dee2e6;">
<td style="padding: 6px 8px; font-weight: 600; color: #2C3E50;">Polling overhead per day</td>
<td style="padding: 6px 8px; text-align: right; color: #16A085; font-weight: 600;">${(pollingOverhead / 1e6).toFixed(2)}M requests</td>
</tr>
<tr>
<td style="padding: 6px 8px; font-weight: 600; color: #2C3E50;">Compromise window vs 1-hour baseline</td>
<td style="padding: 6px 8px; text-align: right; color: ${tokenLifetimeMinutes < 60 ? '#16A085' : tokenLifetimeMinutes > 60 ? '#E74C3C' : '#7F8C8D'}; font-weight: 600;">${tokenLifetimeMinutes < 60 ? compromiseWindowReduction + '% reduction' : tokenLifetimeMinutes > 60 ? Math.abs(((tokenLifetimeMinutes - 60) / 60 * 100)).toFixed(1) + '% increase' : 'baseline'}</td>
</tr>
</table>
<p style="margin: 0.5rem 0 0 0; font-size: 0.85rem; color: #7F8C8D;"><em>Adjust the sliders above to explore cost vs. security trade-offs for different token configurations.</em></p>
</div>`