passport-platform
Service preflight checks and runtime telemetry for Node services.
On startup the service verifies a signed integration token against its own
deployment URL, sends a small telemetry heartbeat, and stops if the preflight
fails. The decision is made locally; the heartbeat endpoint is never required
for the service to start.
The package holds no keys, secrets or product identifiers. The consuming
application supplies all of them.
Install
npm install passport-platform
- Node.js ≥ 18 for the core entry point (uses the global
fetch); the
passport-platform/nest entry point needs Node.js ≥ 20, as NestJS 11 does.
- The
passport-platform/nest entry point additionally needs
@nestjs/common 11, @nestjs/core 11 and rxjs 7 (optional peer
dependencies; the core entry point does not load them).
NestJS
import { Module } from '@nestjs/common';
import { PassportPlatformModule } from 'passport-platform/nest';
@Module({
imports: [
PassportPlatformModule.forRoot({
product: 'my-service',
marker: { name: 'x-my-header', value: '<value>' },
heartbeatUrl: 'https://telemetry.example/beat',
}),
],
})
export class AppModule {}
product: identifier sent with every heartbeat.
marker: a response header set on every HTTP response through a global
interceptor.
heartbeatUrl: heartbeat endpoint. Keep it in application code rather than
in the environment.
getEnv (optional): environment reader, process.env by default.
The module verifies tokens against the Ed25519 public key built into the
package. To use a different key, call enforceLicense from the core entry point
directly.
The module runs the preflight in onApplicationBootstrap. It is skipped
under Jest (JEST_WORKER_ID is set).
Core API
import {
verifyLicenseToken,
evaluateLicense,
hostnameOf,
sendHeartbeat,
enforceLicense,
markerHeaders,
} from 'passport-platform';
verifyLicenseToken(token, publicKeyPem) | Verifies a <payload>.<signature> token (base64url, Ed25519) and returns { domain, exp } or null. |
evaluateLicense({ token, appUrl, nodeEnv, now, publicKeyPem }) | Returns { status, shouldExit }, where status is valid, invalid, domain_mismatch, expired or missing. |
hostnameOf(appUrl) | Lower-cased hostname of a URL, or null. |
sendHeartbeat({ url, product, domain, version, status, timeoutMs? }) | POSTs { product, domain, version, status, at } as JSON. Times out after timeoutMs (default 2000 ms), swallows all errors, does nothing without url. |
enforceLicense({ getEnv, logger, publicKeyPem, product, heartbeatUrl?, now?, exit? }) | Evaluates, sends the heartbeat to heartbeatUrl (if set), then exits with code 1 if shouldExit. |
markerHeaders({ name, value }) | { [name]: value }. |
Environment
LICENSE_KEY | The signed integration token. |
APP_URL | Public URL of this deployment; its hostname must match the token's domain. |
APP_VERSION | Reported in the heartbeat (unknown if unset). |
NODE_ENV | A missing token stops the service only when it is production. |
Behavior
- The start decision depends only on local inputs: the token,
APP_URL,
NODE_ENV, the public key and the current time. No remote call is involved.
- The heartbeat is sent before a failing service exits. Network errors and
timeouts are ignored.
- On failure the default exit sets
process.exitCode = 1, calls
process.exit(1) and throws if that call returns.
Development
npm test
npm run build
npm run verify:pack
License
UNLICENSED. All rights reserved. Use requires permission of the owner.