npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

license-authpkg

v1.5.0

Published

Client library for license key validation and activation

Downloads

21

Readme

License Client

A robust, production-ready license key validation and activation client library for Node.js applications. This package provides everything you need to integrate license key management into your projects.

Features

  • Online & Offline Validation - Works even when disconnected from the internet
  • 🔒 Hardware Fingerprinting - Bind licenses to specific devices
  • 🔄 Automatic Heartbeat - Periodic license verification in the background
  • 🎯 Feature Flags - Control which features are enabled per license tier
  • Grace Period - Configurable offline validation period
  • 📊 Event System - React to license events in your application
  • 🛡️ Security - Cryptographic token verification and validation
  • 💾 Persistent Storage - Secure local storage of activation data
  • 🎨 TypeScript Support - Fully typed for excellent IDE support
  • WebSocket Real-Time - Instant license revocation and updates
  • 📈 Telemetry & Analytics - Built-in usage tracking and monitoring
  • 🔒 Force Shutdown - Remote application termination capability

Installation

npm install @yourorg/license-client

CLI Tool

After installation, you can use the CLI tool to help with setup:

# Encrypt your product ID
npx license-client encrypt my-product-id

# Create a config file template
npx license-client init

# Show help
npx license-client help

Quick Start

Note: This package uses encrypted configuration. The API URL is built-in and encrypted.

Two Product ID Modes:

  1. Pre-assigned: Generate encrypted product IDs using createEncryptedProductId()
  2. Server-assigned: Let your license server assign product IDs dynamically through your web panel

See USAGE.md for detailed setup instructions.

import { LicenseClient, createEncryptedProductId } from '@yourorg/license-client';

// First, generate your encrypted product ID (do this once):
// const encrypted = createEncryptedProductId('your-product-id');
// console.log(encrypted);

// Use the encrypted product ID in your code
const ENCRYPTED_PRODUCT_ID = 'U2FsdGVkX1+xxxxx...'; // From above step

// Create a license.config.json file with your license key:
// {
//   "licenseKey": "XXXX-XXXX-XXXX-XXXX"
// }

// Initialize the client (license key loaded from config file)
const license = new LicenseClient({
  encryptedProductId: ENCRYPTED_PRODUCT_ID
});

// Activate the license (if not already activated)
if (!license.isActivated()) {
  const result = await license.activate();
  
  if (result.success) {
    console.log('License activated!');
  }
}

// Validate the license
const validation = await license.validate();

if (validation.valid) {
  console.log('License is valid');
  
  // Check specific features
  if (license.hasFeature('premium_features')) {
    // Enable premium features
  }
}

Configuration

LicenseConfig Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | encryptedProductId | string | required | Encrypted product identifier (use createEncryptedProductId()) | | licenseKey | string | from config | License key (loaded from config file if not provided) | | configPath | string | auto-detect | Path to config file (.env, license.config.json, or license.config.js) | | storagePath | string | '.license' | Path to store activation data | | offlineGracePeriod | number | 7 | Days before requiring online validation | | heartbeatInterval | number | 24 | Hours between automatic validations | | autoHeartbeat | boolean | true | Enable automatic background validation | | timeout | number | 10000 | API request timeout in milliseconds | | debug | boolean | false | Enable debug logging | | publicKey | string | '' | Public key for offline validation |

Note: The API URL is encrypted and built into the package. It cannot be changed without rebuilding the package.

API Reference

LicenseClient

Methods

activate(licenseKey?: string): Promise<ActivationResult>

Activate the license on the current device.

const result = await license.activate('XXXX-XXXX-XXXX-XXXX');

if (result.success) {
  console.log('Activated!', result.activationData);
} else {
  console.error('Activation failed:', result.message);
}
deactivate(): Promise<{ success: boolean; message: string }>

Deactivate the license from the current device.

const result = await license.deactivate();
console.log(result.message);
validate(): Promise<ValidationResult>

Validate the license (tries online first, falls back to offline).

const result = await license.validate();

if (result.valid) {
  console.log('License is valid');
  if (result.offline) {
    console.log('Validated offline');
  }
} else {
  console.error('Invalid license:', result.message);
}
heartbeat(): Promise<HeartbeatResult>

Manually send a heartbeat to verify the license.

const result = await license.heartbeat();
console.log('License valid:', result.licenseValid);
getStatus(): LicenseStatus

Get comprehensive license status information.

const status = license.getStatus();

console.log('Valid:', status.isValid);
console.log('Activated:', status.isActivated);
console.log('Days until expiration:', status.daysUntilExpiration);
console.log('In grace period:', status.inGracePeriod);
hasFeature(featureName: string): boolean

Check if a specific feature is enabled.

if (license.hasFeature('advanced_reporting')) {
  // Show advanced reporting features
}

if (license.hasFeature('api_access')) {
  // Enable API access
}
getLicenseInfo(): LicenseInfo | null

Get detailed license information.

const info = license.getLicenseInfo();

if (info) {
  console.log('License type:', info.licenseType);
  console.log('Expires:', info.expiresAt);
  console.log('Features:', info.features);
  console.log('Activations:', info.activationsUsed, '/', info.activationLimit);
}
isActivated(): boolean

Check if license is currently activated.

if (!license.isActivated()) {
  // Show activation prompt
}
on(eventType: LicenseEventType, callback: LicenseEventCallback): void

Subscribe to license events.

license.on('activated', (event) => {
  console.log('License activated!', event.data);
});

license.on('expired', (event) => {
  console.log('License expired!');
  // Show renewal prompt
});

license.on('revoked', (event) => {
  console.log('License was revoked');
  // Disable application
});

license.on('grace_period', (event) => {
  if (event.data.expired) {
    console.log('Grace period expired - please connect to internet');
  }
});
destroy(): void

Clean up resources (stop heartbeat, clear event listeners).

license.destroy();

Event Types

  • activated - License was successfully activated
  • deactivated - License was deactivated
  • validated - License validation completed
  • expired - License has expired
  • revoked - License was revoked
  • heartbeat - Heartbeat verification completed
  • error - An error occurred
  • grace_period - Grace period status changed

Usage Examples

Basic Application Protection

import { LicenseClient } from '@yourorg/license-client';

async function initializeApp() {
  const license = new LicenseClient({
    apiUrl: 'https://license.yourapp.com',
    productId: 'my-app',
    licenseKey: process.env.LICENSE_KEY
  });

  // Check if already activated
  if (!license.isActivated()) {
    console.log('Please activate your license');
    const result = await license.activate();
    
    if (!result.success) {
      console.error('Activation failed:', result.message);
      process.exit(1);
    }
  }

  // Validate license
  const validation = await license.validate();
  
  if (!validation.valid) {
    console.error('Invalid license:', validation.message);
    process.exit(1);
  }

  console.log('Application started with valid license');
  
  // Start your application
  startApplication();
}

initializeApp();

Feature-Gated Application

const license = new LicenseClient({
  apiUrl: 'https://license.yourapp.com',
  productId: 'my-app'
});

// Check license tier and enable features accordingly
const status = license.getStatus();

if (status.isValid) {
  const info = license.getLicenseInfo();
  
  console.log(`Welcome! You have a ${info.licenseType} license`);
  
  // Enable features based on license
  const features = {
    basicFeatures: true,
    advancedReporting: license.hasFeature('advanced_reporting'),
    apiAccess: license.hasFeature('api_access'),
    customBranding: license.hasFeature('custom_branding'),
    multiUser: license.hasFeature('multi_user_support')
  };
  
  startApplication(features);
}

CLI Tool with License Management

import { LicenseClient } from '@yourorg/license-client';
import * as readline from 'readline';

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

const license = new LicenseClient({
  apiUrl: 'https://license.yourapp.com',
  productId: 'my-cli-tool'
});

async function promptForLicense() {
  return new Promise<string>((resolve) => {
    rl.question('Enter your license key: ', (key) => {
      resolve(key);
    });
  });
}

async function main() {
  if (!license.isActivated()) {
    const key = await promptForLicense();
    const result = await license.activate(key);
    
    if (result.success) {
      console.log('✓ License activated successfully!');
    } else {
      console.error('✗ Activation failed:', result.message);
      process.exit(1);
    }
  }

  const validation = await license.validate();
  
  if (!validation.valid) {
    console.error('✗ License is invalid:', validation.message);
    
    if (validation.errorCode === 'GRACE_PERIOD_EXPIRED') {
      console.log('Please connect to the internet to verify your license');
    }
    
    process.exit(1);
  }

  // Run your CLI tool
  runCLITool();
  
  rl.close();
}

main();

Web Server with License Validation

import express from 'express';
import { LicenseClient } from '@yourorg/license-client';

const app = express();
const license = new LicenseClient({
  apiUrl: 'https://license.yourapp.com',
  productId: 'my-web-service',
  licenseKey: process.env.LICENSE_KEY
});

// Middleware to check license
app.use(async (req, res, next) => {
  const status = license.getStatus();
  
  if (!status.isValid) {
    return res.status(403).json({
      error: 'Invalid or expired license',
      message: 'Please contact support to renew your license'
    });
  }
  
  next();
});

// Feature-gated endpoints
app.get('/api/advanced-report', (req, res) => {
  if (!license.hasFeature('advanced_reporting')) {
    return res.status(403).json({
      error: 'Feature not available',
      message: 'Upgrade your license to access advanced reporting'
    });
  }
  
  // Generate advanced report
  res.json({ report: 'Advanced report data...' });
});

app.listen(3000, async () => {
  // Validate license on startup
  const validation = await license.validate();
  
  if (!validation.valid) {
    console.error('Invalid license - server will not start');
    process.exit(1);
  }
  
  console.log('Server running with valid license');
});

Desktop Application with UI

import { LicenseClient } from '@yourorg/license-client';

const license = new LicenseClient({
  apiUrl: 'https://license.yourapp.com',
  productId: 'my-desktop-app',
  debug: true
});

// Listen to license events and update UI
license.on('activated', (event) => {
  showNotification('License activated successfully!');
  updateUIForValidLicense();
});

license.on('expired', (event) => {
  showNotification('Your license has expired', 'warning');
  showRenewalDialog();
});

license.on('grace_period', (event) => {
  if (event.data.expired) {
    showNotification('Please connect to internet to verify license', 'warning');
  }
});

// Check status periodically and update UI
setInterval(() => {
  const status = license.getStatus();
  updateStatusBar(status);
  
  if (status.daysUntilExpiration !== null && status.daysUntilExpiration <= 7) {
    showExpirationWarning(status.daysUntilExpiration);
  }
}, 60000); // Every minute

function updateStatusBar(status: LicenseStatus) {
  const statusElement = document.getElementById('license-status');
  
  if (status.isValid) {
    const info = license.getLicenseInfo();
    statusElement.textContent = `License: ${info.licenseType} - Valid`;
    statusElement.className = 'status-valid';
  } else {
    statusElement.textContent = 'License: Invalid';
    statusElement.className = 'status-invalid';
  }
}

Types

LicenseInfo

interface LicenseInfo {
  licenseKey: string;
  licenseType: 'trial' | 'basic' | 'pro' | 'enterprise' | 'lifetime';
  status: 'active' | 'expired' | 'suspended' | 'revoked';
  productId: string;
  customerEmail?: string;
  customerName?: string;
  activationLimit: number;
  activationsUsed: number;
  createdAt: Date;
  activatedAt?: Date;
  expiresAt?: Date;
  features: string[];
  metadata?: Record<string, any>;
}

LicenseStatus

interface LicenseStatus {
  isValid: boolean;
  isActivated: boolean;
  licenseInfo?: LicenseInfo;
  daysUntilExpiration?: number | null;
  remainingActivations?: number;
  lastVerified?: Date;
  daysSinceVerification?: number;
  inGracePeriod: boolean;
}

Error Handling

The library provides specific error classes for different scenarios:

import {
  LicenseError,
  LicenseValidationError,
  LicenseActivationError,
  LicenseExpiredError,
  LicenseRevokedError,
  NetworkError
} from '@yourorg/license-client';

try {
  const result = await license.activate();
} catch (error) {
  if (error instanceof LicenseExpiredError) {
    console.log('License has expired - show renewal options');
  } else if (error instanceof LicenseRevokedError) {
    console.log('License was revoked - contact support');
  } else if (error instanceof NetworkError) {
    console.log('Network error - try offline validation');
  } else if (error instanceof LicenseError) {
    console.log('License error:', error.code, error.message);
  }
}

Best Practices

  1. Store License Keys Securely - Never hardcode license keys in your source code
  2. Graceful Degradation - Handle offline scenarios gracefully
  3. User Feedback - Provide clear messages about license status
  4. Event Handling - Listen to license events to update UI
  5. Error Handling - Catch and handle license errors appropriately
  6. Periodic Checks - Validate license periodically during application runtime
  7. Clean Shutdown - Call destroy() when your application exits

Security Notes

  • Activation data is stored locally in .license file by default
  • Device fingerprinting uses multiple hardware identifiers
  • Offline validation uses cryptographic token verification
  • All API communications should use HTTPS
  • Activation tokens are signed and verified
  • Grace period prevents abuse of offline mode

Server Requirements

This client library requires a compatible license server. The server must provide these endpoints:

  • POST /api/license/activate - Activate a license
  • POST /api/license/deactivate - Deactivate a license
  • POST /api/license/validate - Validate a license
  • POST /api/license/verify-heartbeat - Verify license heartbeat

Documentation

License

MIT License - see LICENSE file for details

Support

For issues, questions, or contributions, please visit: https://github.com/yourorg/license-client

Changelog

1.0.0

  • Initial release
  • Online and offline validation
  • Hardware fingerprinting
  • Automatic heartbeat
  • Event system
  • TypeScript support