All guides

How to Run a License Check at App Startup Without Blocking the Window

Validate software licenses without slowing launch. Use verified offline tokens, background checks and timeouts while honoring expiry and revocation.

Desktop licensing illustration for How to Run a License Check at App Startup Without Blocking the Window

A license check at app startup has two jobs. Open the app promptly and decide which features the customer can use. You can render the first window without waiting for the network, then update the entitlement after a background check.

Open the window and verify local proof

Show the shell and let people reach license settings and their files. If your policy permits offline access, verify the cached signed token against a trusted key and the expected device and product. Check expiry on each use. A missing or invalid token leaves paid features restricted until the server confirms access. A previously confirmed revocation must survive a restart so a stale offline token cannot restore access.

PermitCore's explicit offline flow accepts a server-issued signed token through ActivateOffline or activate_offline, then uses ValidateOffline or validate_offline to check it locally. Configure the trusted public key and use the same device and product context at both steps. Follow the offline licensing setup before relying on the cache.

Run the online check after launch

Run one validation per license at a time. Use a short timeout, then retry transient failures with a little random delay. Honor a server's retry window for rate limits. Validation uses the validate endpoint; device activation remains a separate step. The following callbacks return the SDK result to your app's entitlement handler. Call them after the window is rendered.

C#

static async Task<LicenseResult> CheckAfterLaunchAsync(
    PermitCoreClient client, string key, Guid productId,
    CancellationToken windowClosing)
{
    using var timeout = CancellationTokenSource.CreateLinkedTokenSource(windowClosing);
    timeout.CancelAfter(TimeSpan.FromSeconds(2));
    return await client.ValidateAsync(key, expectedProductId: productId,
        ct: timeout.Token);
}

Python

import asyncio

async def check_after_launch(client, key, product_id):
    return await asyncio.to_thread(
        client.validate, key, expected_product_id=product_id
    )

Set timeout=2 when constructing the Python client. In a desktop toolkit, run the call on its worker mechanism if it does not use asyncio and marshal the result back to the UI thread. An asyncio cancellation does not stop an already-running worker thread, so keep the SDK timeout and ignore results for closed windows or replaced keys.

Handle valid, denied and unknown separately

  • Verified online: apply the entitlement for the selected product. Obtain a newly issued signed token through your trusted issuer when its remaining lifetime falls below your renewal threshold.
  • Explicit denial: handle the documented revoked, expired and wrong-product results. Persist the decision for that key, device and product, and invalidate the app's offline authorization for it. Keep the recovery UI available.
  • Unknown: a timeout, network failure or 503 leaves entitlement unresolved. An SDK result sourced from an offline cache is still offline. Keep only the access backed by current, verified local proof and its existing expiry. Authentication or response-format errors need diagnosis and should never mint or extend offline access.

Use the API error reference to classify authoritative denials. Display a quiet status for outages and a specific recovery action for denials. If paid access expires offline, preserve documents and let users reconnect or enter another key.

Test the transition and measure first paint

In an integration fixture, delay the validation response beyond the timeout, return HTTP 503, then return an authoritative revocation. The first two cases preserve an unexpired offline grant and leave an expired or missing grant restricted. Revocation must stop paid access and remain effective after restarting with the old token on disk. Repeat with a wrong product, a changed device, a corrupted token and a rolled-back clock. Treat unexpected clock changes as a reason to verify online under your policy.

Record time to first interactive window and time to online entitlement separately. Compare p95 cold starts with normal latency, offline and a delayed backend. Keep network time out of the first measurement. See the outage guide for longer interruptions and the license error guide for recovery messages.

Put the guide into practice

Build your first licensed product without building a license server.

Create a free PermitCore account, issue a test license, and validate it from your application.