OpenLicensd

Open source license server for creating and validating license keys

Self-hosted. Single binary. PostgreSQL-backed.
[![CI](https://github.com/alvarorg14/openlicensd/actions/workflows/ci.yml/badge.svg)](https://github.com/alvarorg14/openlicensd/actions/workflows/ci.yml) [![SDK CI](https://github.com/alvarorg14/openlicensd/actions/workflows/sdk-ci.yml/badge.svg)](https://github.com/alvarorg14/openlicensd/actions/workflows/sdk-ci.yml) [![codecov](https://codecov.io/gh/alvarorg14/openlicensd/graph/badge.svg)](https://codecov.io/gh/alvarorg14/openlicensd) [![Vulnerability Scan](https://github.com/alvarorg14/openlicensd/actions/workflows/vuln.yml/badge.svg)](https://github.com/alvarorg14/openlicensd/actions/workflows/vuln.yml) [![CodeQL](https://github.com/alvarorg14/openlicensd/actions/workflows/codeql.yml/badge.svg)](https://github.com/alvarorg14/openlicensd/actions/workflows/codeql.yml) [![Trivy](https://github.com/alvarorg14/openlicensd/actions/workflows/trivy.yml/badge.svg)](https://github.com/alvarorg14/openlicensd/actions/workflows/trivy.yml) [![Release](https://github.com/alvarorg14/openlicensd/actions/workflows/release.yml/badge.svg)](https://github.com/alvarorg14/openlicensd/actions/workflows/release.yml) [![Latest Release](https://img.shields.io/github/v/release/alvarorg14/openlicensd)](https://github.com/alvarorg14/openlicensd/releases) [![License](https://img.shields.io/github/license/alvarorg14/openlicensd)](https://github.com/alvarorg14/openlicensd/blob/main/LICENSE) [![GHCR](https://img.shields.io/badge/GHCR-ghcr.io%2Falvarorg14%2Fopenlicensd-blue)](https://github.com/alvarorg14/openlicensd/pkgs/container/openlicensd) [![Helm OCI](https://img.shields.io/badge/Helm-oci%3A%2F%2Fghcr.io%2Falvarorg14%2Fcharts%2Fopenlicensd-0F1689)](https://github.com/alvarorg14/openlicensd/pkgs/container/charts%2Fopenlicensd) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/alvarorg14/openlicensd/pulls)
[![Go](https://img.shields.io/badge/Go-00ADD8?style=for-the-badge&logo=go&logoColor=white)](https://go.dev/) [![Vue](https://img.shields.io/badge/Vue-4FC08D?style=for-the-badge&logo=vue.js&logoColor=white)](https://vuejs.org/) [![Nuxt](https://img.shields.io/badge/Nuxt-00DC82?style=for-the-badge&logo=nuxt.js&logoColor=white)](https://nuxt.com/) [![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?style=for-the-badge&logo=postgresql&logoColor=white)](https://www.postgresql.org/) [![Helm](https://img.shields.io/badge/Helm-0F1689?style=for-the-badge&logo=helm&logoColor=white)](https://helm.sh/) [![Docker](https://img.shields.io/badge/Docker-2496ED?style=for-the-badge&logo=docker&logoColor=white)](https://www.docker.com/)
[Documentation](https://alvarorg14.github.io/openlicensd/) ยท [Quick Start](#-quick-start) ยท [API](#-api) ยท [Configuration](#%EF%B8%8F-configuration) ยท [Contributing](#-contributing)
--- ## ๐Ÿ“‹ Table of Contents - [๐Ÿ”‘ OpenLicensd](#-openlicensd) - [๐Ÿ“‹ Table of Contents](#-table-of-contents) - [๐Ÿ“– Overview](#-overview) - [๐Ÿค” Why OpenLicensd?](#-why-openlicensd) - [โš–๏ธ Comparison](#๏ธ-comparison) - [โœจ Features](#-features) - [๐Ÿš€ Quick Start](#-quick-start) - [๐Ÿ“ก API](#-api) - [โš™๏ธ Configuration](#๏ธ-configuration) - [๐Ÿ”ง How It Works](#-how-it-works) - [๐Ÿณ Harbor Registry Credentials](#-harbor-registry-credentials) - [๐Ÿ” OIDC SSO](#-oidc-sso) - [๐Ÿ’ป Local Development](#-local-development) - [๐Ÿค Contributing](#-contributing) - [๐Ÿ”’ Security](#-security) - [๐Ÿ“„ License](#-license) --- ## ๐Ÿ“– Overview **OpenLicensd** is a self-hosted license server for creating, managing, and validating license keys. It ships as a single Go binary with an embedded Nuxt admin UI and stores data in PostgreSQL. Use it to gate access to your software, issue time-limited keys, track validation usage, and optionally provide short-lived Harbor registry credentials to licensed clients.
OpenLicensd admin UI licenses list
## ๐Ÿค” Why OpenLicensd? - **Self-hosted** โ€” no third-party license service dependency - **Single binary** โ€” API and admin UI in one deployable artifact - **Simple API** โ€” public validation endpoint for client applications - **Harbor integration** โ€” optional short-lived registry credentials for container image distribution - **OIDC SSO** โ€” optional single sign-on via any standards-compliant identity provider - **Kubernetes-ready** โ€” Helm chart with Ingress, External Secrets, and health probes ## โš–๏ธ Comparison How OpenLicensd compares to [Keygen](https://keygen.sh/), [Cryptlex](https://cryptlex.com/), and [LicenseSpring](https://licensespring.com/). See [docs/comparison.md](docs/comparison.md) for the full breakdown with source links. | | OpenLicensd | Keygen | Cryptlex | LicenseSpring | |---|---|---|---|---| | **License** | Apache 2.0 (fully OSS) | Fair Core (source-available) | Proprietary | Proprietary | | **Managed SaaS** | No | Yes (Keygen Cloud) | Yes | Yes | | **Self-host option** | Yes (only model) | Yes (CE free, EE paid) | Yes (Enterprise) | Yes (Enterprise) | | **Cost model** | Free (your infra) | CE free; EE + Cloud paid | Subscription tiers | Subscription tiers | | **Self-host runtime** | Single binary + PostgreSQL | Rails + PostgreSQL + Redis | Multi-service platform | Vendor platform + on-prem server | **Choose OpenLicensd when** you want a fully open-source, single-binary, self-hosted license server with no per-seat fees, a simple validation API, Harbor credential integration, and Kubernetes-ready deployment. **Consider an alternative when** you need managed SaaS, offline/signed licenses, entitlements, webhooks, floating seats with heartbeats, a customer self-service portal, release distribution, built-in billing, or client SDKs beyond Go. ## โœจ Features - Admin UI with sidebar navigation for licenses, products, and policies - **Products** โ€” scope licenses to an application (identified by a unique `code`) - **Policies** โ€” per-product expiration rules (duration, basis, grace period) - License creation requires a product and policy; expiration is derived from the policy - Optional manual expiration override per license - Usage tracking (`last_validated_at` and `validation_count`) - **Max activations** โ€” limit concurrent machines per license key (policy default, per-license override) - Machine activation tracking with admin release and rename - Public validation endpoint with optional product scoping, machine fingerprint, and grace period support - Human-readable Crockford Base32 key format (`XXXXX-XXXXX-XXXXX-XXXXX-XXXXX`); validation accepts case- and dash-insensitive Crockford variants - Optional Harbor registry credentials endpoint (short-lived robot accounts) - Optional OIDC SSO for admin login (Google, Entra ID, Keycloak, Okta, GitLab, and other providers) - **API tokens** โ€” scoped, revocable Bearer credentials for CI, Terraform, and other automation - **Audit log** โ€” append-only record of admin mutations (who, what, when, IP) for compliance - Single binary distribution with embedded UI (published releases: Linux amd64/arm64; see [docs/deployment.md](docs/deployment.md#platforms)) - PostgreSQL storage with automatic migrations - Prometheus metrics on a dedicated listener (`/metrics` on `:9090` by default) - Helm chart for Kubernetes deployment ## ๐Ÿš€ Quick Start > **New here?** See [QUICKSTART.md](QUICKSTART.md) for a step-by-step get-running guide. Container images are published to `ghcr.io/alvarorg14/openlicensd` on release (image tags: `X.Y.Z`, `X.Y`, `latest`; git tags: `vX.Y.Z`). The Helm chart is published to `oci://ghcr.io/alvarorg14/charts/openlicensd`. ```bash helm install openlicensd oci://ghcr.io/alvarorg14/charts/openlicensd \ --version X.Y.Z \ --namespace openlicensd \ --create-namespace ``` Try the published image with Docker Compose (pin with `OPENLICENSD_IMAGE_TAG=X.Y.Z` for production): ```bash make stack-up ``` Open http://localhost:8080 and sign in with `admin@example.com` / `admin`. For local development: ```bash make dev-db cp .env.example .env make dev-server # terminal 1 make dev-ui # terminal 2 ``` Open http://localhost:3000 and sign in with `admin` / `admin`. ## ๐Ÿ“ก API The HTTP API is specified in [docs/openapi.yaml](docs/openapi.yaml) (OpenAPI 3.1). That file is the source of truth for paths, schemas, and status codes. See [docs/api.md](docs/api.md) for authentication, roles, and curl examples. **Public** (no auth; rate limited per client IP): `POST /api/v1/validate` and, when Harbor is enabled, `POST /api/v1/registry-credentials`. **Admin** (session or Bearer; rate limited per user or API token): all other `/api/v1/*` routes except login/OIDC callback and `GET /auth/providers`. **Admin** (session cookie or `Authorization: Bearer`; CSRF on session writes): products, policies, licenses, machines, users, API tokens, and audit events. Token management (`/api/v1/api-tokens`) requires an admin session. **Health**: `GET /healthz` (liveness), `GET /readyz` (readiness, PostgreSQL ping). ## Client SDKs Official client libraries for integrating license validation into your applications: | Language | Package | Docs | |----------|---------|------| | Go | [`github.com/alvarorg14/openlicensd/sdk/go`](https://pkg.go.dev/github.com/alvarorg14/openlicensd/sdk/go) | [docs/sdk/go.md](docs/sdk/go.md) | ```go import openlicensd "github.com/alvarorg14/openlicensd/sdk/go" fp, _ := openlicensd.Fingerprint("my-cli") client, _ := openlicensd.New( "https://licenses.example.com", "acme-widget", openlicensd.WithFingerprint(fp), ) result, _ := client.Validate(ctx, licenseKey) ``` ## โš™๏ธ Configuration | Variable | Default | Description | |----------|---------|-------------| | `OPENLICENSD_ADDR` | `:8080` | HTTP listen address | | `OPENLICENSD_DATABASE_HOST` | *(required)* | PostgreSQL host | | `OPENLICENSD_DATABASE_PORT` | `5432` | PostgreSQL port | | `OPENLICENSD_DATABASE_USER` | *(required)* | PostgreSQL user | | `OPENLICENSD_DATABASE_PASSWORD` | โ€” | PostgreSQL password | | `OPENLICENSD_DATABASE_NAME` | *(required)* | PostgreSQL database name | | `OPENLICENSD_DATABASE_SSLMODE` | `require` | PostgreSQL `sslmode` | | `OPENLICENSD_DATABASE_MAX_CONNS` | `0` | Maximum pool connections (`0` = pgx default) | | `OPENLICENSD_DATABASE_MIN_CONNS` | `0` | Minimum pool connections (`0` = pgx default) | | `OPENLICENSD_DATABASE_MAX_CONN_IDLE_MINUTES` | `0` | Idle connection lifetime in minutes (`0` = pgx default) | | `OPENLICENSD_DATABASE_STATEMENT_TIMEOUT_SECONDS` | `0` | PostgreSQL statement timeout in seconds (`0` = server default) | | `OPENLICENSD_BOOTSTRAP_ADMIN_EMAIL` | โ€” | Email for first admin (required on empty database) | | `OPENLICENSD_BOOTSTRAP_ADMIN_PASSWORD_HASH` | โ€” | Bcrypt hash for bootstrap admin password | | `OPENLICENSD_SESSION_TTL_HOURS` | `24` | Session lifetime in hours | | `OPENLICENSD_REQUEST_TIMEOUT_SECONDS` | `30` | Per-request context deadline in seconds (`0` disables) | | `OPENLICENSD_REQUEST_BODY_MAX_BYTES` | `1048576` | Maximum HTTP request body size in bytes | | `OPENLICENSD_SESSION_CLEANUP_INTERVAL_MINUTES` | `60` | Interval for deleting expired/revoked sessions (`0` disables) | | `OPENLICENSD_AUDIT_RETENTION_DAYS` | `0` | Delete audit events older than this many days (`0` disables; requires cleanup interval > 0) | | `OPENLICENSD_AUDIT_CLEANUP_INTERVAL_MINUTES` | `1440` | Interval for audit retention pruning when retention days > 0 (`0` disables the background job) | | `OPENLICENSD_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, or `error` | | `OPENLICENSD_LOG_FORMAT` | `json` | Log output format: `json` or `text` | | `OPENLICENSD_METRICS_ENABLED` | `true` | Enable Prometheus `/metrics` on a dedicated listener | | `OPENLICENSD_METRICS_ADDR` | `:9090` | Metrics listen address (must differ from `OPENLICENSD_ADDR`) | | `OPENLICENSD_COOKIE_SECURE` | `true` | Set `Secure` flag on session cookies and enable HSTS headers (`false` for local HTTP) | Rate limiting, metrics, database pool, and trusted-proxy variables (`OPENLICENSD_RATE_LIMIT_*`, including optional `OPENLICENSD_RATE_LIMIT_BACKEND=postgres` for multi-replica deployments, `OPENLICENSD_METRICS_*`, `OPENLICENSD_DATABASE_*`, `OPENLICENSD_TRUSTED_PROXIES`) are documented in [docs/configuration.md](docs/configuration.md). See [docs/metrics.md](docs/metrics.md) for the Prometheus metric catalog, [docs/scaling.md](docs/scaling.md) for HA and multi-replica guidance, and [docs/troubleshooting.md](docs/troubleshooting.md) for common failure diagnosis. Generate a password hash: ```bash make hash-password PASSWORD=yourpassword ``` ## ๐Ÿ”ง How It Works ```mermaid flowchart LR subgraph admin [Admin] ui[Admin UI] end subgraph openlicensd [OpenLicensd] api[API Server] store[(PostgreSQL)] end subgraph clients [Clients] app[Application] docker[Docker CLI] end ui -->|session cookie| api app -->|POST /validate| api docker -->|POST /registry-credentials| api api --> store ``` 1. Admins manage licenses through the embedded UI or the REST API. 2. Client applications validate license keys via the public `/validate` endpoint. 3. When Harbor integration is enabled, licensed clients can obtain short-lived registry credentials. 4. License keys are stored as SHA-256 hashes; only the key prefix is retained for display. See [docs/architecture.md](docs/architecture.md) for component details and data flows. ## ๐Ÿณ Harbor Registry Credentials When `OPENLICENSD_HARBOR_ENABLED=true`, licensed clients can exchange a valid license key for short-lived Harbor robot account credentials with pull access to configured projects. ```bash curl -s -X POST https://licenses.example.com/api/v1/registry-credentials \ -H "Content-Type: application/json" \ -d '{"key":"X4F9K-7QP2M-3RH8N-BW6TG-YZ2CD"}' ``` See [docs/harbor-registry-credentials.md](docs/harbor-registry-credentials.md) for setup, configuration, and troubleshooting. ## ๐Ÿ” OIDC SSO When `OPENLICENSD_OIDC_ENABLED=true`, admins can sign in through any standards-compliant OIDC identity provider (Google, Entra ID, Keycloak, Okta, GitLab, and others). Users are provisioned on first login when the IdP issues `email_verified: true`; roles are managed locally in the admin UI. Register this redirect URI with your IdP: ``` https:///api/v1/auth/oidc/callback ``` See [docs/oidc-sso.md](docs/oidc-sso.md) for setup, configuration, and troubleshooting. ## ๐Ÿ’ป Local Development Requires Go 1.27+, Node.js 24+, and Docker (for local PostgreSQL). Run `make help` to list all available targets: ```bash make dev-db # Start PostgreSQL make dev-db-reset # Reset dev PostgreSQL volume make dev-server # Run API server (loads .env) make dev-ui # Run Nuxt dev server make stack-up # Start Postgres + openlicensd from GHCR image make stack-down # Stop full stack (ARGS=-v to drop data) make stack-logs # Tail full stack logs make build # Build UI + binary make test # Run Go tests make lint # go vet + golangci-lint + ESLint (same as CI) ``` A plain `go build` embeds a placeholder admin page; run `make build` (or `make ui` first) for the full admin UI. See [AGENTS.md](AGENTS.md) for architecture details and AI assistant guidelines. ## ๐Ÿค Contributing Contributions are welcome! Issues and pull requests help make this project better for everyone. - See [ROADMAP.md](ROADMAP.md) for the path to v1.0 and open work - Read [CHANGELOG.md](CHANGELOG.md) for server version history - Read [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow - Read [SUPPORT.md](SUPPORT.md) for support channels and version guidance - Read [COMPATIBILITY.md](COMPATIBILITY.md) for API stability and deprecation policy (from v1.0.0) - Follow our [Code of Conduct](CODE_OF_CONDUCT.md) - See [AGENTS.md](AGENTS.md) if you're an AI assistant or want deeper architecture context ## ๐Ÿ”’ Security If you discover a security vulnerability, please report it via a private GitHub security advisory. Do **not** open a public issue. See [SECURITY.md](SECURITY.md) for the full security policy, including [which versions receive security patches](SECURITY.md#supported-versions). For production deployment hardening and go-live checklists, see [docs/security-hardening.md](docs/security-hardening.md) and [docs/production-checklist.md](docs/production-checklist.md). **Dependency maintenance:** Renovate batches non-major Go module, npm, Docker, and GitHub Actions updates into weekly pull requests per ecosystem. Major upgrades stay in separate PRs. Install the [Renovate GitHub App](https://github.com/apps/renovate) on this repository to enable it. **Vulnerability scanning:** A separate Vulnerability Scan workflow runs govulncheck weekly, on demand, and on pull requests (non-blocking) to detect known vulnerabilities in Go dependencies. **Static analysis:** A CodeQL workflow runs on push, pull requests, and weekly to scan Go (server and SDK) and TypeScript (admin UI) source for security issues. Results appear in the repository [Security tab](https://github.com/alvarorg14/openlicensd/security/code-scanning). **Container scanning:** A Trivy workflow scans the OpenLicensd container image on pull requests (built from `Dockerfile`), after server releases (published GHCR tag), and weekly on `ghcr.io/alvarorg14/openlicensd:latest`. Results appear in the repository [Security tab](https://github.com/alvarorg14/openlicensd/security/code-scanning). **SBOMs:** Server releases attach SPDX JSON Software Bill of Materials files generated by [Syft](https://github.com/anchore/syft) โ€” one per linux archive and one per GHCR image platform. Download them from the [Releases](https://github.com/alvarorg14/openlicensd/releases) page alongside binaries and checksums. **Image signing and provenance:** Published GHCR container images are signed with keyless [Cosign](https://github.com/sigstore/cosign) and include a GitHub Artifact Attestation with SLSA build provenance. Verify a release image with: ```bash cosign verify \ --certificate-identity-regexp 'https://github.com/alvarorg14/openlicensd/\.github/workflows/release\.yml@.*' \ --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \ ghcr.io/alvarorg14/openlicensd@sha256: gh attestation verify oci://ghcr.io/alvarorg14/openlicensd:X.Y.Z -R alvarorg14/openlicensd ``` Replace `X.Y.Z` with the image tag (semver without the `v` prefix) and `` with the image SHA-256 digest. ## ๐Ÿ“„ License [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) Apache License 2.0 โ€” see [LICENSE](LICENSE) and [NOTICE](NOTICE). --- Made with โค๏ธ using Go, Vue, and PostgreSQL