DEV Community

Cover image for Offline License Verification Has a Local Trust Limit
Raylabs
Raylabs

Posted on Originally published at raylabs.app

Offline License Verification Has a Local Trust Limit

Browser extensions operating offline struggle to validate paid tiers securely without exposing private signing keys. When building such systems, developers must also understand monetization strategies like those discussed in How Chrome Extensions Actually Make Money, ensuring that offline checks complement broader revenue models without introducing brittle dependencies.

Quick solution:
Verify a base64url-encoded cryptographic signature inside your extension runtime using the Web Crypto signature verification interface before unlocking pro features:

async function verifyLicense(publicKey, signatureBytes, payloadBytes) {
  return await crypto.subtle.verify(
    { name: "ECDSA", hash: { name: "SHA-256" } },
    publicKey,
    signatureBytes,
    payloadBytes
  );
}
Enter fullscreen mode Exit fullscreen mode

Prerequisites: The public key must be hardcoded or securely provisioned during extension installation. Caution: Never bundle the private signing key inside the extension package, as anyone can extract it from unpacked extension directories.

Shipping software that functions offline while validating paid tiers requires a delicate balance between user convenience and security. Developers often build extensions that must operate without a constant network connection. An offline license can be verified with a public key while its signing key stays outside the distributed client. A signature establishes authenticity of license data, but it does not make client-side feature gates tamper-proof against a determined user who controls the local runtime.

What Belongs in the Signed Payload

A secure license payload must contain specific metadata to prevent replay attacks, unauthorized tier escalation, and indefinite usage without renewal. Minimizing the scope of what is signed keeps the payload compact and easy to parse inside a restricted extension background worker.

The signed payload should include the licensee identifier, the product or SKU identifier, an issued timestamp, an explicit expiration timestamp, and a unique license key identifier or version number to support future key rotations. According to guidelines outlined in RFC 8725 JWT best current practices, tokens and signed statements must explicitly define their intended audience and validity window to mitigate token substitution attacks.

{
  "sub": "user_9f8e7d6c5b4a",
  "sku": "pro-tier-annual",
  "iat": 1776470400,
  "exp": 1808006400,
  "kid": "key-2026-01"
}
Enter fullscreen mode Exit fullscreen mode

Including unnecessary fields increases the payload size and expands the surface area for parsing vulnerabilities. Keep the schema flat and strict.

Why Must the Signing Secret Stay Out of Extension Code

Browser extensions are distributed as client-side packages that users can download, unpack, and inspect. Any code or asset included in the extension bundle is fully accessible to the end user. If a developer places the private signing key inside the extension source code to generate licenses locally, users can easily extract that key.

Once a malicious user obtains the private signing key, they can generate valid, cryptographically signed licenses for themselves or others. This completely breaks the monetization model. The signing secret must reside exclusively on a secure server or an isolated build pipeline that only the developer or authorized backend service can access. The extension package must contain only the matching public key used exclusively for read-only verification.

How Revocation and Clock Rollback Affect Offline Operation

Offline verification introduces inherent limitations around revocation status and system time integrity. When an extension has no network connectivity, it cannot query a remote revocation list to check if a specific license key has been revoked due to a refund, chargeback, or security compromise.

To mitigate this, developers use short-lived expiration windows, such as thirty days, forcing the extension to periodically reconnect and download a fresh signed payload. However, this introduces another vulnerability vector: system clock rollback. A user might manually set their operating system clock backward to bypass the expiration check.

Challenge When it occurs Failure mode Recommended mitigation
Revocation check Device is offline Revoked license remains active until next sync Enforce short expiration windows (7-30 days)
Clock rollback User changes OS time Expired license appears valid indefinitely Validate time against last known network timestamp or secure NTP
Unknown key ID After key rotation Valid signature rejected due to missing public key Bundle multiple active public keys and check key ID headers

Handling these edge cases requires accepting that offline trust is bounded. If absolute tamper-proof verification is required, the application must require an online connection.

Verification Checklist

  • Confirm that a modified payload string fails cryptographic verification and triggers the fallback free tier.
  • Verify that an unknown key identifier is correctly rejected even if the signature format is otherwise valid.
  • Test expired and malformed payloads to ensure they throw explicit handling errors rather than crashing the extension runtime.
  • Ensure no private signing keys or sensitive server-side environment variables exist within the extension build artifacts.

Top comments (0)