@usertour/license
v0.0.2
Published
JWT license signing and validation utilities for UserTour
Maintainers
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/licenseQuick 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 tokengenerateLicenseWithInfo(options: GenerateLicenseOptions)- Generate license with additional infodecodeToken(token: string): JWTLicensePayload | null- Decode token without verificationgetTokenInfo(token: string)- Get complete token information
JWTLicenseValidator
Static Methods
validateLicense(license, publicKey, options?)- Validate a JWT licensevalidateRequiredFields(payload)- Validate payload structurecheckExpiration(payload, currentTime?)- Check if license is expiredhasFeature(payload, feature)- Check if license has specific featuregetExpirationInfo(payload, currentTime?)- Get expiration detailsdecodeLicense(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
- Private Key Security: Keep your RSA private keys secure and never expose them in client-side code
- Public Key Distribution: Distribute public keys securely to validation endpoints
- Token Storage: Store JWT tokens securely and consider token rotation policies
- 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.
