Skip to content

Repository files navigation

Glassefc SaaS

Multi-platform license management platform for software publishers. Activate, validate, monitor, and secure licenses across desktop, mobile, and web applications.


Table of Contents


Overview

Glassefc is a license management platform that provides cryptographic license validation, device binding, and multi-platform SDK support. The platform is designed for software publishers who need to enforce licensing across desktop, mobile, and web applications without compromising offline usability or security.

The system uses Ed25519 digital signatures for offline-capable license validation, device fingerprinting for hardware binding, and refresh token rotation for secure session management. All SDKs share a common validation core, ensuring consistent behavior across platforms.


Core Capabilities

License Management

Capability Description
Creation Generate licenses with configurable plan-tier limits, expiry, and device caps
Activation Bind a license to a device using hardware fingerprint
Validation Cryptographically verify license state offline and online
Blocking Toggle license block state to instantly revoke access
Extension Extend license expiry without regenerating keys
Device Replacement Deauthorize old hardware and authorize replacement
Device Revocation Remove device bindings from a license

Security

Capability Description
Ed25519 Signatures All validation responses signed with Ed25519 keypairs
Replay Protection Nonce + timestamp validation via Redis
Key Rotation Versioned Ed25519 keypairs with rotation support
Device Fingerprinting Hardware-bound device identity verification
Audit Logging All admin actions logged with actor, IP, and metadata
Security Events Suspicious activity detection and recording
Rate Limiting Per-endpoint limits with brute force protection
Offline Validation Signed token cache with configurable grace period
Refresh Token Rotation Rotating refresh token lifecycle with automatic renewal

Developer Experience

Capability Description
Multi-Platform SDKs Native SDKs for iOS, Android, Flutter, Web, Next.js, Vue, React Native, Electron, Tauri
API-First Design RESTful API with consistent patterns across all endpoints
Admin Dashboard Web-based dashboard for license and device management
Docker Support Containerized deployment for API, dashboard, and services
CI/CD Pipelines GitHub Actions workflows for testing and publishing
Prometheus Metrics Built-in observability with Prometheus-compatible metrics

Architecture

flowchart LR
    subgraph Client["Client Side"]
        direction TB
        SDK["SDK Layer"]
        SIG["Signature Verification"]
        LOCK["Lock Enforcement"]
        CACHE["Cache + Offline Store"]
    end

    subgraph Gateway["Gateway Layer"]
        direction TB
        GW["API Gateway"]
        RL["Rate Limiter"]
        RSV["Request Sig Validator"]
        RP["Replay Protection (Nonce)"]
    end

    subgraph Core["Core Services"]
        direction TB
        LE["License Engine"]
        DM["Device Manager"]
        ACT["Activation Service"]
        SUB["Subscription Service"]
    end

    subgraph Security["Security Layer"]
        direction TB
        ES["Ed25519 Signer"]
        KM["Key Manager"]
        TG["Token Generator"]
        AUD["Audit Logger"]
    end

    subgraph Data["Data Layer"]
        direction TB
        PGPRIMARY["PostgreSQL Primary"] --> PGREPLICA["Read Replica Pool"]
        RCACHE["Redis Cache"]
        RNONCE["Redis Nonce Store"]
    end

    subgraph Admin["Admin Side"]
        DASH["Dashboard UI"]
        ADMINAPI["Admin API"]
        BILL["Billing Service"]
        ANALYTICS["Analytics Service"]
    end

    subgraph Obs["Observability"]
        PROM["Prometheus"]
        GRAF["Grafana"]
        LOKI["Loki"]
        ALERT["Alertmanager"]
    end

    Client -- "License Check" --> Gateway
    Gateway -- "Validated Request" --> Core
    Core -- "Token Signing" --> Security
    Security -- "Data Lookup" --> Data

    Security -. "Signed License Token" .-> Client

    Admin -. "Admin Operations" .-> Core

    Client -. "Metrics" .-> Obs
    Gateway -. "Metrics" .-> Obs
    Core -. "Metrics" .-> Obs
    Security -. "Metrics" .-> Obs
    Data -. "Metrics" .-> Obs
Loading

The platform is composed of five logical layers that form a complete request lifecycle:

Layer Role
Client Side Platform-specific SDKs handle device fingerprinting, Ed25519 signature verification, local token caching with offline validation, and lock enforcement when a license is invalid, expired, or blocked.
Gateway Layer API Gateway receives signed HTTPS requests, applies rate limiting per endpoint, validates incoming request signatures, and enforces replay protection via nonce checks against Redis. Only validated requests reach core services.
Core Services License Engine processes validation logic, Device Manager tracks hardware bindings, Activation Service registers new devices, and Subscription Service enforces plan-tier limits.
Security Layer Ed25519 Signer cryptographically signs all validation responses, Key Manager handles key generation and rotation, Token Generator creates signed license tokens, and Audit Logger records all administrative actions.
Data Layer PostgreSQL Primary handles all write operations (activation, device binding, license revocation). Read Replica Pool serves validation and analytics queries. Redis provides both cache storage and nonce-based replay protection.

A dark-themed SVG architecture diagram is available at docs/architecture/glassefc-architecture.svg suitable for presentations and documentation. Editable versions are also available for Excalidraw and Draw.io.


Supported Platforms

Platform SDK Package Language Distribution
iOS sdk-swift Swift Swift Package Manager
Android sdk-android Kotlin Maven Central
Flutter sdk-flutter Dart pub.dev
Web (Vanilla) sdk-js TypeScript npm
Next.js sdk-nextjs TypeScript npm
Vue.js sdk-vue TypeScript npm
React Native sdk-react-native TypeScript npm
Electron sdk-electron TypeScript npm
Tauri sdk-tauri Rust + TypeScript crates.io + npm

Repository Structure

glassefc-saas/
├── apps/
│   ├── api/                       # Fastify API server
│   │   ├── src/
│   │   │   ├── routes/            # Endpoint handlers
│   │   │   ├── plugins/           # Fastify plugins
│   │   │   └── lib/               # Shared utilities
│   │   ├── test/
│   │   └── package.json
│   └── dashboard/                 # Next.js 14 admin panel
│       ├── src/
│       │   ├── app/               # App router pages
│       │   ├── components/        # React components
│       │   └── lib/               # API client, queries
│       ├── public/
│       └── package.json
├── packages/
│   ├── sdk-core/                  # Shared validation logic (TypeScript)
│   ├── sdk-js/                    # Web SDK
│   ├── sdk-nextjs/                # Next.js SDK (context + hooks)
│   ├── sdk-vue/                   # Vue SDK (plugin + composable)
│   ├── sdk-react-native/          # React Native SDK (hooks + lock overlay)
│   ├── sdk-electron/              # Electron SDK (main/preload/renderer)
│   ├── sdk-tauri/                 # Tauri SDK (Rust core + TS bindings)
│   ├── sdk-swift/                 # iOS Swift package
│   ├── sdk-android/               # Android Kotlin library
│   └── sdk-flutter/               # Flutter Dart package
├── services/
│   ├── license-engine/            # License validation, signing, activation
│   └── security/                  # Key management, encryption, audit
├── prisma/
│   ├── schema.prisma              # Database schema
│   └── migrations/                # Migration history
├── infra/
│   ├── docker/                    # Dockerfiles for each service
│   ├── nginx/                     # Reverse proxy configs
│   └── postgres/                  # Init scripts
├── .github/
│   └── workflows/                 # CI/CD pipelines
├── turbo.json                     # Turborepo configuration
├── pnpm-workspace.yaml            # PNPM workspace definition
└── package.json                   # Root package.json

Getting Started

Prerequisites

  • Node.js 20+
  • PNPM 9+
  • Docker (for local PostgreSQL and Redis)
  • PostgreSQL 16+
  • Redis 7+

Installation

# Clone the repository
git clone https://github.com/your-org/glassefc-saas.git
cd glassefc-saas

# Install dependencies
pnpm install

# Copy environment variables
cp .env.example .env

# Start database and cache services
docker compose up -d postgres redis

# Run database migrations
pnpm db:migrate

# Start development servers
pnpm dev

The API server starts at http://localhost:3001 and the dashboard at http://localhost:3000.

Configuration

Environment variables for the API server:

Variable Description Default
DATABASE_URL PostgreSQL connection string postgresql://localhost:5432/glassefc
REDIS_URL Redis connection string redis://localhost:6379
JWT_SECRET JWT signing secret for admin auth --
API_PORT API server port 3001
CORS_ORIGIN Allowed CORS origin for dashboard http://localhost:3000
ENCRYPTION_KEY Key for encrypting private keys at rest --

Local Development

Commands

# Start all services in development mode
pnpm dev

# Start only the API server
pnpm dev --filter=api

# Start only the dashboard
pnpm dev --filter=dashboard

# Build all packages
pnpm build

# Run tests across all packages
pnpm test

# Lint all packages
pnpm lint

# Generate Prisma client
pnpm db:generate

# Create a migration
pnpm db:migrate:dev

# Open Prisma Studio
pnpm db:studio

Adding a New SDK

  1. Create a new package under packages/sdk-<platform> using the existing SDKs as reference.
  2. Implement the SDK interface defined in sdk-core:
    • checkLicense(licenseKey, deviceFingerprint) -- validates license online
    • validateCachedToken() -- validates locally cached signed token
    • activateLicense(licenseKey, deviceFingerprint) -- binds device to license
    • Event callbacks for license state changes and lock overlay triggers
  3. Import and re-export the core validation functions from sdk-core.
  4. Register the new package in pnpm-workspace.yaml.
  5. Add GitHub Actions workflows for automated testing on PR.

License Validation Flow

Client App                  SDK                      API Server              Database / Redis
    │                        │                           │                       │
    │  Initialization        │                           │                       │
    │───────────────────────▶│                           │                       │
    │                        │  Check cached token       │                       │
    │                        ├───────────────────────────x                       │
    │                        │  ◀── No valid cache ──────┤                       │
    │                        │                           │                       │
    │  checkLicense(key,fp)  │                           │                       │
    │───────────────────────▶│  POST /license/check      │                       │
    │                        │──────────────────────────▶│                       │
    │                        │                           │  Validate license     │
    │                        │                           ├──────────────────────▶│
    │                        │                           │  ◀── license data ────┤
    │                        │                           │                       │
    │                        │                           │  Check device match   │
    │                        │                           ├──────────────────────▶│
    │                        │                           │  ◀── device data ─────┤
    │                        │                           │                       │
    │                        │                           │  Check replay nonce   │
    │                        │                           ├────── (Redis) ───────▶│
    │                        │                           │  ◀── OK/expired ──────┤
    │                        │                           │                       │
    │                        │                           │  Sign response with   │
    │                        │                           │  Ed25519              │
    │                        │                           │                       │
    │                        │  ◀── Signed token ────────┤                       │
    │                        │                           │                       │
    │                        │  Verify Ed25519 sig       │                       │
    │                        │  Cache token locally       │                       │
    │                        │  Return license state      │                       │
    │  ◀── LicenseResult ────┤                           │                       │
    │                        │                           │                       │

The validation flow uses a cache-first strategy:

  1. On initialization, the SDK checks for a locally cached signed token.
  2. If a valid token exists and has not expired, it is verified using the cached public key and returned immediately.
  3. If no valid cache exists, the SDK sends POST /license/check with the license key and device fingerprint.
  4. The API validates the license exists, is not blocked, and has not expired.
  5. The API verifies the device fingerprint matches the bound device (if activated).
  6. The API checks the replay nonce in Redis to prevent token reuse.
  7. A signed token is returned containing the license state, device ID, and expiry.
  8. The SDK verifies the Ed25519 signature using the public key fetched from /.well-known/public-keys/:appId.
  9. The SDK caches the validated token and fires the appropriate callback.

Offline Validation

When the device is offline, the SDK validates the cached signed token without contacting the API:

SDK Offline Path
    │
    ├── Load cached token from secure storage
    ├── Verify Ed25519 signature with cached public key
    ├── Check token expiry (default grace: 72 hours)
    ├── Check license state (active, blocked, expired)
    └── Return validation result or fire lock callback

The signed token contains all data needed for offline validation, eliminating the need for network access during the grace period.


API Overview

License Endpoints

Method Path Description
POST /license/check Validate license and device. Returns Ed25519-signed token
POST /license/activate Register a device to a license using device fingerprint
POST /license/refresh/request Request a refresh token for device rotation
POST /license/refresh Rotate refresh token, return new signed license

Admin Endpoints

Method Path Description
POST /admin/app/create Register a new application. Auto-generates Ed25519 keypair
GET /admin/apps List applications owned by the authenticated user
POST /admin/license/create Create a license with plan-tier device limits and expiry
POST /admin/license/block/:id Toggle license block state
POST /admin/license/extend Extend license expiry date
GET /admin/devices List devices with pagination, search, and filter
POST /admin/device/revoke Revoke a device binding (soft delete)
POST /admin/device/replace Replace an old device binding with a new device
GET /admin/audit-logs Paginated audit log of all admin actions
GET /admin/security-events Paginated security events

Public Key Endpoints

Method Path Description
GET /.well-known/public-key/:keyId Retrieve a specific public key by key ID
GET /.well-known/public-keys/:appId List all active public keys for an application

Example

import { Glassefc } from '@glassefc/sdk-js'

const glassefc = new Glassefc({
  appId: 'app_abc123',
  publicKey: '-----BEGIN PUBLIC KEY-----...',
})

const result = await glassefc.checkLicense({
  licenseKey: 'LIC-XXXX-YYYY-ZZZZ',
  deviceFingerprint: await glassefc.getDeviceFingerprint(),
})

if (result.valid) {
  // License is valid -- proceed with application
} else {
  // License is invalid, expired, or blocked
  glassefc.showLockOverlay(result.reason)
}

Security Model

Cryptographic Signing

All license validation responses are signed with Ed25519 keypairs. Each application registered in the system is issued a unique keypair upon creation. The private key is encrypted at rest using AES-256-GCM and is only decrypted in memory during signing operations.

Replay Protection

Each signed token includes a nonce and timestamp. The nonce is stored in Redis with a TTL matching the token validity period. If the same nonce is presented again, the request is rejected. This prevents token replay attacks even if a signed token is intercepted.

Key Rotation

Keys can be rotated through the admin dashboard or API. When a key is rotated:

  1. A new keypair is generated and marked as the active signing key.
  2. The previous key remains available for verification until all tokens signed with it expire.
  3. Old keys are automatically removed from /.well-known/public-keys after all tokens signed with them have expired.

Device Binding

Each device is identified by a fingerprint derived from hardware characteristics. The fingerprint is generated by the SDK on the client device and sent during license activation and check. Once a license is activated on a device, validation checks enforce that the fingerprint matches the one stored during activation.

Audit Trail

All administrative actions are logged with:

  • Actor ID and role
  • IP address and user agent
  • Action type and affected resources
  • Before/after state for mutations
  • ISO 8601 timestamp

Rate Limiting

Rate limits are applied per endpoint using a sliding window algorithm backed by Redis:

Endpoint Group Limit Window
License check 60 requests 1 minute
License activation 10 requests 1 minute
Admin endpoints 120 requests 1 minute
Public key endpoints 300 requests 1 minute

SDK Ecosystem

All SDKs share a common validation core (sdk-core) that implements the following contract:

interface LicenseSDK {
  initialize(config: SDKConfig): void
  checkLicense(input: CheckInput): Promise<CheckResult>
  activateLicense(input: ActivateInput): Promise<ActivationResult>
  validateLocalToken(): CheckResult | null
  onLicenseValid(callback: (result: CheckResult) => void): void
  onLicenseInvalid(callback: (reason: string) => void): void
  onLockRequired(callback: (reason: string) => void): void
  getDeviceFingerprint(): Promise<string>
  getCachedLicenseState(): CachedState | null
  clearCache(): void
}

Platform-Specific Adaptations

SDK Language Key Adaptation
sdk-js TypeScript Web crypto API for signature verification
sdk-nextjs TypeScript React context provider + hooks, SSR-compatible initialization
sdk-vue TypeScript Vue plugin + composable useLicense
sdk-react-native TypeScript Native device fingerprinting via RN modules, full-screen lock overlay component
sdk-electron TypeScript Main/preload/renderer architecture, machine ID for fingerprinting
sdk-tauri Rust + TS Rust core for signature verification, Tauri command bindings
sdk-swift Swift CryptoKit for Ed25519 verification, device fingerprint via IOKit
sdk-android Kotlin Android Keystore for secure storage, HardwareAttestation for fingerprinting
sdk-flutter Dart Method channels for native device fingerprinting, Dart crypto for signature verification

Deployment

Docker Compose (Production)

version: '3.8'
services:
  api:
    build:
      context: .
      dockerfile: infra/docker/api.Dockerfile
    environment:
      - DATABASE_URL=postgresql://postgres:password@postgres:5432/glassefc
      - REDIS_URL=redis://redis:6379
      - JWT_SECRET=${JWT_SECRET}
      - ENCRYPTION_KEY=${ENCRYPTION_KEY}
    depends_on:
      - postgres
      - redis
    ports:
      - '3001:3001'
    restart: unless-stopped

  dashboard:
    build:
      context: .
      dockerfile: infra/dashboard.Dockerfile
    environment:
      - NEXT_PUBLIC_API_URL=https://api.glassefc.example.com
    ports:
      - '3000:3000'
    restart: unless-stopped

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: glassefc
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data
    restart: unless-stopped

volumes:
  pgdata:
  redis-data:

Environment Variables (Production)

Variable Required Description
DATABASE_URL Yes PostgreSQL connection string
REDIS_URL Yes Redis connection string
JWT_SECRET Yes Secret for JWT token signing (min 32 chars)
ENCRYPTION_KEY Yes AES-256 key for private key encryption (32 bytes, hex-encoded)
CORS_ORIGIN Yes Dashboard URL for CORS configuration
NODE_ENV Yes production
LOG_LEVEL No Logging level (info, warn, error). Default: info
RATE_LIMIT_MAX No Global rate limit. Default: 100

Database Migrations

# Run migrations in production
pnpm db:migrate:deploy

# Generate Prisma client (included in Docker build)
pnpm db:generate

Reverse Proxy (Nginx)

server {
    listen 443 ssl;
    server_name api.glassefc.example.com;

    location / {
        proxy_pass http://api:3001;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /.well-known/ {
        proxy_pass http://api:3001;
        proxy_cache_valid 200 5m;
        add_header Cache-Control "public, max-age=300";
    }
}

server {
    listen 443 ssl;
    server_name dashboard.glassefc.example.com;

    location / {
        proxy_pass http://dashboard:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Observability

Health Check

curl https://api.glassefc.example.com/health
{
  "status": "ok",
  "uptime": 482301,
  "version": "1.2.0",
  "database": "connected",
  "redis": "connected"
}

Prometheus Metrics

Metrics are exposed at /metrics in Prometheus text format:

Metric Type Description
license_checks_total Counter Total license check requests
license_activations_total Counter Total license activations
license_validation_duration_ms Histogram License validation latency
active_licenses Gauge Currently active licenses
blocked_licenses Gauge Currently blocked licenses
device_count Gauge Total registered devices
api_request_duration_ms Histogram API request latency by endpoint
rate_limit_exceeded_total Counter Rate-limited requests

Logging

Structured JSON logging is used across all services:

{
  "level": "info",
  "timestamp": "2026-06-17T10:30:00.000Z",
  "service": "license-engine",
  "action": "license_check",
  "licenseId": "lic_abc123",
  "appId": "app_def456",
  "deviceId": "dev_789012",
  "result": "valid",
  "durationMs": 12
}

Roadmap

  • Concurrent license enforcement (per-seat limits across devices)
  • Floating licenses with lease-based allocation
  • License templates and bulk creation
  • Webhook events for license state changes
  • Billing integration (Stripe, Paddle, Lemon Squeezy)
  • On-premise deployment guides (Kubernetes, Nomad)
  • License analytics dashboard with usage reporting
  • Feature flags gated by license tier
  • gRPC API for low-latency validation
  • Plugin system for custom validation rules

Contributing

This repository uses PNPM workspaces and Turborepo for monorepo management.

# Setup
pnpm install
pnpm build

# Run tests before committing
pnpm test

# Lint
pnpm lint

# Format
pnpm format

All SDKs share a common validation interface defined in packages/sdk-core. Platform-specific implementations should import from sdk-core rather than duplicating validation logic.

Pull requests should include tests covering the changed behavior. Each package has its own test suite run via Turborepo's test pipeline.


License

MIT

About

No description, website, or topics provided.

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages