JavaScript SDK for the fast, file-backed, scalable JSON token engine
Escape the JWT trap: predictable login, safe logout
Fast B-tree–backed token store for stateful user sessions
Provides authentication and authorization across multiple processes
Optimized for vertical scaling on a single server
npm install crudjt- One process starts the master
- All other processes connect to it
Start the CRUDJT master when your application boots
Only one process should do this
The master is responsible for session state and coordination
All functions can also be used directly from it
For containerized deployments, see: Start CRUDJT master in Docker
export CRUDJT_SECRET_KEY=$(openssl rand -base64 48)const CRUDJT = require('crudjt');
await CRUDJT.Config.startMaster({
secret_key: process.env.CRUDJT_SECRET_KEY,
store_jt_path: 'path/to/local/storage', // optional
grpc_host: '127.0.0.1', // default
grpc_port: 50051 // default
});
// Use await CRUDJT.Config.shutdownServer() to shut down the gRPC server and let
// the process exitImportant: Use the same secret_key across all sessions. If the key changes, previously stored tokens cannot be decrypted and will return null or false
Create a docker-compose.yml file:
services:
crudjt-server:
image: crudjt/crudjt-server:latest
restart: unless-stopped
ports:
- "${CRUDJT_CLIENT_PORT:-50051}:50051"
volumes:
- "${STORE_JT:-./store_jt}:/app/store_jt"
- "${CRUDJT_SECRETS:-./crudjt_secrets}:/app/secrets"
environment:
CRUDJT_DOCKER_HOST: 0.0.0.0
CRUDJT_DOCKER_PORT: 50051Start the server:
docker-compose up -dEnsure the secrets directory contains your secret key file at ./crudjt_secrets/secret_key.txt
For configuration details and image versions, see the CRUDJT Server on Docker Hub
Use this in all other processes
Typical examples:
- multiple local processes
- background jobs
- forked processes
const CRUDJT = require('crudjt');
CRUDJT.Config.connectToMaster({
grpc_host: '127.0.0.1', // default
grpc_port: 50051 // default
});App boot
├─ Process A → start_master
├─ Process B → connect_to_master
└─ Process C → connect_to_master
const data = { user_id: 42, role: 11 }; // required
const ttl = 3600 * 24 * 30; // optional: token lifetime (seconds)
// Optional: read limit
// Each read decrements the counter
// When it reaches zero — the token is deleted
const silenceRead = 10;
const token = await CRUDJT.create(data, ttl, silenceRead);
// token === 'HBmKFXoXgJ46mCqer1WXyQ'// To disable token expiration or read limits, pass `null`
const token = await CRUDJT.create(
{ user_id: 42, role: 11 },
null, // disable TTL
null // disable read limit
);const result = await CRUDJT.read('HBmKFXoXgJ46mCqer1WXyQ');
// result === { metadata: { ttl: 101001, silence_read: 9 }, data: { user_id: 42, role: 11 } }// When expired or not found token
const result = await CRUDJT.read('HBmKFXoXgJ46mCqer1WXyQ');
// result === nullconst data = { user_id: 42, role: 8 };
// `null` disables limits
const ttl = 600;
const silenceRead = 100;
const result = await CRUDJT.update('HBmKFXoXgJ46mCqer1WXyQ', data, ttl, silenceRead);
// result === true// When expired or not found token
const result = await CRUDJT.update('HBmKFXoXgJ46mCqer1WXyQ', { user_id: 42, role: 8 });
// result === falseconst result = await CRUDJT.delete('HBmKFXoXgJ46mCqer1WXyQ');
// result === true// When expired or not found token
const result = await CRUDJT.delete('HBmKFXoXgJ46mCqer1WXyQ');
// result === false40 000 requests up to 256 bytes — median over 10 runs
macOS 15.7.4, ARM64 (Apple M1)
JavaScript 20.20.0
In-process benchmark; Redis accessed via localhost TCP
| Function | CRUDJT (JavaScript) | JWT (JavaScript) | redis-session-store (Ruby, Rails 8.0.2.1) |
|---|---|---|---|
| C | 0.372 second |
16.537 seconds | 2.909 seconds |
| R | 0.010 second |
16.678 seconds | 4.436 seconds |
| U | 0.684 second |
X | 2.124 seconds |
| D | 0.200 second |
X | 3.984 seconds |
40 000 tokens of 256 bytes each — median over 10 creates
darwin23, APFS
48 MB
Stored tokens are placed in the file system according to the following order
- Explicitly set via
CRUDJT.Config.startMaster({store_jt_path: 'custom/path/to/file_system_db'}); - Default system location
- Linux:
/var/lib/store_jt - macOS:
/usr/local/var/store_jt - Windows:
C:\Program Files\store_jt
- Linux:
- Project root directory (fallback)
- CRUDJT automatically removing expired tokens after start and every 24 hours without blocking the main thread
- Storage automatically fsyncs every 500ms, meanwhile tokens are available from cache
For multi-process scenarios, CRUDJT uses gRPC over an insecure local port for same-host communication only. It is not intended for inter-machine or internet-facing usage
The library has the following limits and requirements
- Node version: >= 18.0.0
- Supported platforms: Linux, macOS, Windows (x86_64 / arm64)
- Maximum json size per token: 256 bytes
secret_keyformat: must be Base64secret_keysize: must be 32, 48, or 64 bytes
- Custom integrations / new features / collaboration: [email protected]
- Library support & bug reports: open an issue
CRUDJT is released under the MIT License
💘 Shoot your g . ? Love me out via Patreon Sponsors!