Handle browser-token refresh in a long-running IllyVoIP SDK session

Handle scheduled and manual IllyVoIP SDK token refresh, deferred application during calls, authorization failures and cleanup in a long-running session.

A browser calling session can outlive its first short-lived authorization token. In managed mode, the IllyVoIP SDK can refresh its bootstrap through your token provider. Keep that provider available for the lifetime of the phone and continue enforcing the user’s current authorization on your backend.

This guide targets SDK 1.4.2 and an existing single phone owner. It explains refresh events, manual refresh and deferred application during a call. It does not replace the framework lifecycle guides or promise that an expired or revoked authorization permits continued calling.

1. Keep the provider reusable and authorized

Do not supply a function that works only once or always returns the first cached token. The provider must be able to obtain a current short-lived token for the SDK’s requested region when refresh occurs.

Your backend must authenticate the current application session and derive the authorized SIP identity on every issuance. Recheck account changes, logout and role removal. A browser component remaining mounted is not proof that its user still has permission to call.

Return the documented token payload, including its expiry information, without leaking the permanent API key or unrelated account data. Use a bounded HTTP request and handle failure explicitly. Do not write tokens or complete bootstrap responses to ordinary logs.

2. Observe refresh separately from registration

function watchRefresh(phone, show) {
  const off = [
    phone.on('credentials:refreshing', () => show('Refreshing authorization')),
    phone.on('credentials:refreshed', () =>
      show('Authorization refreshed; check connection state')),
    phone.on('credentials:refresh-failed', () =>
      show('Authorization refresh failed; review access and connection')),
    phone.on('registration:registered', () => show('Registered')),
    phone.on('registration:unregistered', () => show('Unregistered'))
  ];
  return () => off.forEach(unsubscribe => unsubscribe());
}

show must update plain text and ignore updates after its view is disposed. In a larger application, keep separate authorization, connection, registration and call status fields instead of allowing one label to hide another important condition.

A refreshed event means new bootstrap information was obtained. It is not a certificate that the phone has already re-registered or that a call succeeded. Continue following normal connection and call events.

3. Understand what happens during an active call

When a current call exists, the SDK stores the refreshed bootstrap and defers applying it to the connection. The active-call interface should remain attached to the same owner and call object. Do not tear down the phone simply because a refresh notification arrived.

After the call ends, the SDK attempts to apply the pending bootstrap. Observe registration/connection state and errors during that transition. Obtaining fresh credentials and successfully applying them are separate stages; a later apply failure still needs attention.

This behavior is not a guarantee that any call survives network loss or authorization revocation. Your application must define a deliberate logout and account-switch policy rather than relying on refresh timing as a security boundary.

4. Offer manual refresh only when it helps recovery

The SDK schedules refresh when the managed provider and expiry information permit it. A manual Refresh authorization control can call refreshBootstrap when the underlying access or connectivity problem has been corrected; it should not become an aggressive polling loop.

function manualRefresh(phone, report) {
  let pending = false;
  return async function refresh() {
    if (pending) return false;
    pending = true;
    report('Refreshing');
    try {
      await phone.refreshBootstrap();
      report('Refresh completed; verify current registration');
      return true;
    } catch {
      report('Refresh failed; check authorization before retrying');
      return false;
    } finally {
      pending = false;
    }
  };
}

Keep the helper in the same phone owner, disable its button while pending, and make report safe after UI disposal. A user changing accounts must not refresh the old identity. Raw SIP mode manages credentials directly and rejects this managed-refresh operation.

5. Handle failure without spawning another phone

For a denied token request, check the application session and authorized identity first. For an unavailable backend or network, display a bounded recovery path. Do not silently continue to offer new calls as if authorization were healthy, and do not create another instance while cleanup or reconnect remains uncertain.

If a registration or bootstrap-apply error occurs after the call ends, investigate the current owner’s state. Preserve sanitized event timing and error codes, not the token payload. Coordinate permanent API-key rotation through the separate rotation workflow.

Test long-session behavior

Use fixtures for scheduled refresh, a manual double click, provider rejection, refresh while a call is active, applying after the call ends, logout during a pending request and disposal before a late result. Confirm that the old identity cannot receive newly issued tokens after logout.

Then verify the supported browser and deployment’s real authorization lifecycle during an authorized acceptance session. Passing a mocked refresh test does not prove live registration renewal or uninterrupted audio.

Related guides and reference

Reviewed 10 October 2026 against the current IllyVoIP reference and implementation. SDK examples target version 1.4.2 where applicable. Local example checks do not certify a completed live call, routing change or third-party integration.