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

@usertour/license

v0.0.2

Published

JWT license signing and validation utilities for UserTour

Readme

@usertour/license

JWT license signing and validation utilities for UserTour.

Features

  • 🔐 JWT License Signing: Generate secure JWT-based licenses with RSA signatures
  • License Validation: Validate JWT licenses with comprehensive checks
  • 🎯 Feature Management: Control feature access through license-based feature flags
  • Expiration Handling: Built-in expiration checks and validation
  • 🛡️ Type Safety: Full TypeScript support with comprehensive type definitions

Installation

npm install @usertour/license
# or
yarn add @usertour/license
# or
pnpm add @usertour/license

Quick Start

Signing Licenses

import { JWTLicenseSigner } from '@usertour/license';

const signer = new JWTLicenseSigner({
  privateKeyPath: './path/to/private-key.pem',
  issuer: 'https://your-company.com',
  algorithm: 'RS256'
});

const license = signer.generateLicense({
  plan: 'pro',
  subject: 'My Project',
  projectId: 'project-123',
  expiresInDays: 365,
  features: ['analytics', 'custom-themes', '*'], // '*' means all features
});

console.log('Generated license:', license);

Validating Licenses

import { JWTLicenseValidator } from '@usertour/license';

const publicKey = `-----BEGIN PUBLIC KEY-----
...your RSA public key...
-----END PUBLIC KEY-----`;

const result = JWTLicenseValidator.validateLicense(
  license,
  publicKey,
  {
    checkExpiration: true,
    currentTime: new Date(),
  }
);

if (result.isValid) {
  console.log('License is valid!');
  console.log('Plan:', result.payload?.plan);
  console.log('Project ID:', result.payload?.projectId);
  
  // Check if license has specific features
  const hasAnalytics = result.hasFeature?.('analytics');
  const hasCustomThemes = result.hasFeature?.('custom-themes');
} else {
  console.error('License validation failed:', result.error);
  if (result.isExpired) {
    console.error('License has expired');
  }
}

API Reference

JWTLicenseSigner

Constructor Options

interface JWTLicenseSignerOptions {
  privateKeyPath: string;  // Path to RSA private key file
  issuer?: string;         // JWT issuer (default: 'https://www.usertour.io')
  algorithm?: jwt.Algorithm; // JWT algorithm (default: 'RS256')
}

Methods

  • generateLicense(options: GenerateLicenseOptions): string - Generate a JWT license token
  • generateLicenseWithInfo(options: GenerateLicenseOptions) - Generate license with additional info
  • decodeToken(token: string): JWTLicensePayload | null - Decode token without verification
  • getTokenInfo(token: string) - Get complete token information

JWTLicenseValidator

Static Methods

  • validateLicense(license, publicKey, options?) - Validate a JWT license
  • validateRequiredFields(payload) - Validate payload structure
  • checkExpiration(payload, currentTime?) - Check if license is expired
  • hasFeature(payload, feature) - Check if license has specific feature
  • getExpirationInfo(payload, currentTime?) - Get expiration details
  • decodeLicense(license) - Decode license without verification

Types

JWTLicensePayload

interface JWTLicensePayload {
  plan: string;           // License plan type
  sub: string;            // Subject (project name)
  projectId: string;      // Project identifier
  iat: number;            // Issued at timestamp
  exp: number;            // Expiration timestamp
  issuer: string;         // JWT issuer
  features: string[];     // Array of enabled features
}

JWTLicenseValidationResult

interface JWTLicenseValidationResult {
  isValid: boolean;
  error?: string;
  payload?: JWTLicensePayload;
  isExpired?: boolean;
  hasFeature?: (feature: string) => boolean;
}

Examples

Feature-based Access Control

// Check if license allows specific features
const result = JWTLicenseValidator.validateLicense(license, publicKey);

if (result.isValid && result.hasFeature) {
  const canUseAnalytics = result.hasFeature('analytics');
  const canUseCustomThemes = result.hasFeature('custom-themes');
  const hasAllFeatures = result.hasFeature('*');
  
  // Enable/disable features based on license
  if (canUseAnalytics) {
    enableAnalyticsModule();
  }
  
  if (canUseCustomThemes) {
    enableCustomThemes();
  }
}

License Expiration Handling

const result = JWTLicenseValidator.validateLicense(license, publicKey);

if (result.payload) {
  const expirationInfo = JWTLicenseValidator.getExpirationInfo(result.payload);
  
  console.log('Expires at:', expirationInfo.expiresAt);
  console.log('Days until expiration:', expirationInfo.daysUntilExpiration);
  
  if (expirationInfo.daysUntilExpiration <= 30) {
    showRenewalWarning();
  }
}

Generating Licenses with Custom Data

const licenseInfo = signer.generateLicenseWithInfo({
  plan: 'enterprise',
  subject: 'Acme Corp Project',
  projectId: 'acme-proj-456',
  expiresInDays: 730, // 2 years
  features: ['*'], // All features
  issuer: 'https://acme-licensing.com',
});

console.log('Token:', licenseInfo.token);
console.log('Expires at:', licenseInfo.expiresAt);
console.log('Payload:', licenseInfo.payload);

Security Considerations

  1. Private Key Security: Keep your RSA private keys secure and never expose them in client-side code
  2. Public Key Distribution: Distribute public keys securely to validation endpoints
  3. Token Storage: Store JWT tokens securely and consider token rotation policies
  4. Validation: Always validate licenses on the server side for security-critical operations

License

AGPL-3.0 - see LICENSE for details.

Contributing

See CONTRIBUTING.md for contribution guidelines.

Support