resonate-token-authentication-typescript — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited resonate-token-authentication-typescript (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Resonate supports JWT-based authentication and prefix-based authorization to secure access to the Resonate server and control which promises clients can access. This enables multi-tenant systems, role-based access control, and isolation between different workers or services.
Core principle: Generate JWT tokens signed with a private key, configure the Resonate server with the public key, and clients present tokens to authenticate. Optionally use the prefix claim for fine-grained authorization.
Without Auth:
Client → Resonate Server → All Promises Accessible
With Token Auth:
Client + Valid JWT → Resonate Server → All Promises Accessible
Client + Invalid JWT → Resonate Server → REJECTED (401 Unauthorized)
With Prefix Auth (Multi-Tenant):
Client + JWT(prefix="tenant-1") → Access only "tenant-1:*" promises
Client + JWT(prefix="tenant-2") → Access only "tenant-2:*" promises
Client + JWT(prefix="worker-a") → Access only "worker-a:*" promises# Generate private key (keep this secret!)
openssl genrsa -out private_key.pem 2048
# Extract public key (share with Resonate server)
openssl rsa -in private_key.pem -pubout -out public_key.pemSecurity:
private_key.pem securely (never commit to git, use secrets manager)public_key.pem can be deployed with server configuration# macOS
brew install mike-engel/jwt-cli/jwt-cli
# Other platforms
# https://github.com/mike-engel/jwt-cli#installationBasic authentication token (no prefix):
jwt encode --secret @private_key.pem -A RS256 '{}'Token with prefix claim (for authorization):
jwt encode --secret @private_key.pem -A RS256 '{"prefix":"tenant-1"}'Store token in environment variable:
export MY_TOKEN=$(jwt encode --secret @private_key.pem -A RS256 '{"prefix":"worker-1"}')# Enable JWT authentication
resonate dev --auth-publickey public_key.pemWhat this does:
prefix claim is present# Using Docker
docker run -v $(pwd)/public_key.pem:/keys/public_key.pem \
resonatehq/resonate \
serve --auth-publickey /keys/public_key.pem
# Using systemd service (see `resonate-server-deployment`)
resonate serve \
--auth-publickey /etc/resonate/public_key.pem \
--storage-type postgres \
--storage-postgres-url postgres://user:[email protected]/resonateFor fully worked deploys of the server with auth wired in, see resonate-server-deployment (Linux/systemd) or resonate-server-deployment-cloud-run (GCP Cloud Run + Cloud SQL).
Use when: You want to restrict access to trusted clients only, but all authenticated clients have equal access.
import { Resonate, Context } from "@resonatehq/sdk";
function* helloAuth(ctx: Context, greeting: string) {
const result = yield* ctx.run((ctx: Context) => {
return `${greeting} world!`;
});
return result;
}
// Authenticated client
const resonate = new Resonate({
url: "http://localhost:8001",
token: process.env.MY_TOKEN // JWT token from environment
});
// Register and run workflows
const workflow = resonate.register("workflow", helloAuth);
const result = await workflow.run("workflow.id", "hello");
console.log(result); // "hello world!"
resonate.stop();Without token:
// ❌ This will fail with "ResonateError: The request is unauthorized"
const resonateNoAuth = new Resonate({
url: "http://localhost:8001"
// No token provided
});
const workflow = resonateNoAuth.register("workflow", helloAuth);
await workflow.run("workflow.id", "hello"); // THROWS 401 ERRORUse when: You need to isolate promises between tenants, workers, or services.
When a client connects with a token containing a prefix claim, the Resonate server enforces that the client can only:
Generate tenant-specific tokens:
# Token for Tenant 1
export TENANT1_TOKEN=$(jwt encode -S @private_key.pem -A RS256 '{"prefix":"tenant-1"}')
# Token for Tenant 2
export TENANT2_TOKEN=$(jwt encode -S @private_key.pem -A RS256 '{"prefix":"tenant-2"}')
# Token for Worker A
export WORKER_A_TOKEN=$(jwt encode -S @private_key.pem -A RS256 '{"prefix":"worker-a"}')// Tenant 1 client
const tenant1 = new Resonate({
url: "http://localhost:8001",
token: process.env.TENANT1_TOKEN,
prefix: "tenant-1" // SDK automatically prefixes all promise IDs
});
const workflow1 = tenant1.register("workflow", processOrder);
// Creates promise with ID "tenant-1:order-123"
await workflow1.run("order-123", orderData);
// Tenant 2 client (isolated from Tenant 1)
const tenant2 = new Resonate({
url: "http://localhost:8001",
token: process.env.TENANT2_TOKEN,
prefix: "tenant-2"
});
const workflow2 = tenant2.register("workflow", processOrder);
// Creates promise with ID "tenant-2:order-123"
await workflow2.run("order-123", orderData);
// Tenant 1 cannot access Tenant 2's promises (and vice versa)const resonate = new Resonate({
url: "http://localhost:8001",
token: process.env.TENANT1_TOKEN
// No prefix set in SDK
});
const workflow = resonate.register("workflow", processOrder);
// Manually prefix the promise ID
await workflow.run("tenant-1:order-123", orderData);Why manual prefixing?
Use when: Multiple worker groups should not interfere with each other's promises.
// Worker Group A
const workerA = new Resonate({
url: "http://localhost:8001",
token: process.env.WORKER_A_TOKEN,
prefix: "worker-a",
group: "workers-a"
});
workerA.register("processTask", processTask);
// Worker Group B (isolated from A)
const workerB = new Resonate({
url: "http://localhost:8001",
token: process.env.WORKER_B_TOKEN,
prefix: "worker-b",
group: "workers-b"
});
workerB.register("processTask", processTask);
// Worker A can only claim tasks prefixed with "worker-a:"
// Worker B can only claim tasks prefixed with "worker-b:"Use when: You want to avoid hardcoding credentials in source code.
// Set environment variables
// RESONATE_TOKEN=<jwt-token>
// RESONATE_PREFIX=tenant-1
// SDK automatically reads from environment
const resonate = new Resonate({
url: "http://localhost:8001"
// Token and prefix read from RESONATE_TOKEN and RESONATE_PREFIX
});
const workflow = resonate.register("workflow", myWorkflow);
await workflow.run("order-123", data); // Creates "tenant-1:order-123"Environment variables:
RESONATE_TOKEN: JWT tokenRESONATE_PREFIX: Promise ID prefixUse when: Different roles need different levels of access.
# Admin token (access all promises)
export ADMIN_TOKEN=$(jwt encode -S @private_key.pem -A RS256 '{}')
# Service token (access only service-specific promises)
export SERVICE_TOKEN=$(jwt encode -S @private_key.pem -A RS256 '{"prefix":"service-api"}')
# User token (access only user-specific promises)
export USER_TOKEN=$(jwt encode -S @private_key.pem -A RS256 '{"prefix":"user-${userId}"}')Client code:
// Admin client (no prefix restriction)
const admin = new Resonate({
url: "http://localhost:8001",
token: process.env.ADMIN_TOKEN
});
// Can access any promise ID
await admin.promises.get("tenant-1:order-123");
await admin.promises.get("tenant-2:order-456");
// Service client (restricted to service-api:* promises)
const service = new Resonate({
url: "http://localhost:8001",
token: process.env.SERVICE_TOKEN,
prefix: "service-api"
});
// Can only access "service-api:*" promises
await service.promises.get("request-123"); // OK (becomes "service-api:request-123")Required claims:
{} is valid for basic authentication)Optional claims:
prefix (string): Restricts promise access to IDs starting with this prefixexp (number): Token expiration timestamp (Unix epoch)iat (number): Token issued-at timestampToken validation:
# Generate token with expiration (1 hour)
jwt encode -S @private_key.pem -A RS256 \
--exp='+1 hour' \
'{"prefix":"tenant-1"}'
# Decode and verify token
jwt decode -S @public_key.pem $MY_TOKEN# ❌ WRONG - Committing keys to git
git add private_key.pem # NEVER DO THIS
# ✅ CORRECT - Use secrets manager
aws secretsmanager create-secret \
--name resonate-jwt-private-key \
--secret-string file://private_key.pem
# ✅ CORRECT - Add to .gitignore
echo "*.pem" >> .gitignore
echo "*.key" >> .gitignore# Generate new key pair
openssl genrsa -out private_key_v2.pem 2048
openssl rsa -in private_key_v2.pem -pubout -out public_key_v2.pem
# Update server configuration
resonate serve --auth-publickey public_key_v2.pem
# Issue new tokens with new private key
jwt encode -S @private_key_v2.pem -A RS256 '{"prefix":"tenant-1"}'# Generate short-lived tokens (1 hour)
jwt encode -S @private_key.pem -A RS256 --exp='+1 hour' '{}'
# Generate long-lived tokens (30 days)
jwt encode -S @private_key.pem -A RS256 --exp='+30 days' '{}'// ✅ GOOD - Narrow prefix
const client = new Resonate({
token: token,
prefix: "user-123" // Can only access user-123's promises
});
// ❌ BAD - Wide prefix
const client = new Resonate({
token: token,
prefix: "user" // Can access all users' promises (user-*, user-123, etc.)
});For production systems, integrate with identity providers like:
// Implement token refresh before expiration
let token = await getInitialToken();
let resonate = new Resonate({ url: serverUrl, token });
// Refresh token periodically
setInterval(async () => {
token = await refreshToken(token);
resonate = new Resonate({ url: serverUrl, token });
}, 30 * 60 * 1000); // Refresh every 30 minutes// Log authentication events
resonate.on("error", (error) => {
if (error.message.includes("unauthorized")) {
logger.warn("Authentication failed", {
timestamp: Date.now(),
error: error.message
});
}
});# ❌ WRONG - Server not configured for auth
resonate dev # No --auth-publickey flag
# Client with token connects but auth is not enforced# ✅ CORRECT - Server configured for auth
resonate dev --auth-publickey public_key.pem// Token has prefix="tenant-1"
const token = generateToken({ prefix: "tenant-1" });
// ❌ WRONG - SDK prefix doesn't match token
const resonate = new Resonate({
token: token,
prefix: "tenant-2" // Server will reject requests
});
// ✅ CORRECT - SDK prefix matches token
const resonate = new Resonate({
token: token,
prefix: "tenant-1" // Matches token claim
});// ❌ WRONG - Token exposed in logs
console.log(`Token: ${process.env.MY_TOKEN}`);
// ✅ CORRECT - Redact tokens
console.log(`Token: ${process.env.MY_TOKEN?.slice(0, 10)}...`);Use token authentication when:
Use prefix-based authorization when:
Don't use authentication when:
resonate dev without flags)Token authentication and prefix-based authorization enable:
Core recipe: Generate RSA key pair → Configure server with public key → Generate JWT tokens with prefix claims → Clients authenticate with tokens → Server enforces prefix-based access control
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.