Skip to content
reaatechREAATECH

@reaatech/media-pipeline-mcp-security

npm v0.3.0

Provides authentication (API keys with constant-time comparison, JWT/OAuth2 with HS256), role-based access control (admin/operator/viewer with 10 permissions), token bucket rate limiting, and audit logging with SIEM export for media pipeline deployments. Exports `AuthMiddleware`, `createRateLimiter`, and `createAuditLogger` classes/factories.

@reaatech/media-pipeline-mcp-security

npm version License: MIT CI

Status: Pre-1.0 — APIs may change in minor versions. Pin to a specific version in production.

Enterprise security features for media pipeline deployments. Provides multi-method authentication (API keys with constant-time comparison, JWT/OAuth2 with HS256), role-based access control (admin, operator, viewer with 10 granular permissions), token bucket rate limiting (per-client and per-operation), operation-to-permission mapping for 30+ media operations, and an immutable audit trail with SIEM export to Splunk, Datadog, and Sumo Logic.

Installation

terminal
npm install @reaatech/media-pipeline-mcp-security
# or
pnpm add @reaatech/media-pipeline-mcp-security

Feature Overview

  • API key authentication — constant-time string comparison to prevent timing attacks, per-key permission and tenant mapping
  • JWT/OAuth2 authentication — HS256 token verification with Zod-validated payloads, configurable expiry, role and permission extraction
  • Role-based access control — three roles (admin, operator, viewer) with 10 granular permissions; canPerformOperation maps 30+ media operations to required permissions
  • Token bucket rate limiting — per-client buckets with per-operation sub-buckets, global rate cap, auto-cleanup of stale buckets after 1 hour
  • Standard rate limit headersX-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After
  • Audit logging — 13 event types (authentication, pipeline execution, artifact access, etc.) buffered to disk as JSONL with periodic flush
  • SIEM integration — native exporters for Splunk (HEC), Datadog (Logs API v2), and Sumo Logic (HTTP collector) with re-queue on failure
  • Token generation — JWT token issuance for service accounts with roles and custom permissions
  • Tenant-aware — API key and JWT payload carry tenantId for multi-tenant deployments
  • Secret validation — JWT secrets must be ≥32 characters; missing authentication sources cause construction-time errors when requireAuth is set

Quick Start

typescript
import {
  createRBACMiddleware,
  createRateLimiter,
  createAuditLogger,
} from "@reaatech/media-pipeline-mcp-security";
 
// API key authentication
const auth = createRBACMiddleware({
  apiKeys: new Map([
    ["sk-abc123", { userId: "service-1", permissions: ["pipeline:run", "artifact:read"], tenantId: "tenant-a" }],
  ]),
  requireAuth: true,
});
 
const ctx = await auth.authenticate({ "x-api-key": "sk-abc123" });
console.log(ctx.authenticated);  // true
console.log(ctx.tenantId);       // "tenant-a"
 
// Check permission for an operation
const allowed = auth.canPerformOperation(ctx, "image.generate");
console.log(allowed); // true
 
// Rate limiting
const limiter = createRateLimiter({
  clientRequestsPerMinute: 60,
  clientBurstSize: 10,
  operationLimits: new Map([
    ["image.generate", { requestsPerMinute: 5, burstSize: 2 }],
  ]),
});
 
const result = limiter.checkLimit("client-123", "image.generate");
console.log(result.allowed, result.remaining);  // true, 4
 
// Audit logging
const logger = createAuditLogger({
  bufferSize: 100,
  flushInterval: 5000,
  retentionDays: 30,
});
 
logger.logAuthentication("user-1", "user@example.com", true, "192.168.1.1");

API Reference

AuthMiddleware

Multi-method authentication and RBAC middleware.

typescript
class AuthMiddleware {
  constructor(config: AuthConfig);
 
  authenticate(headers: Record<string, string | undefined>): Promise<AuthContext>;
  hasPermission(context: AuthContext, permission: string): boolean;
  canPerformOperation(context: AuthContext, operation: string): boolean;
  generateToken(user: { id: string; email: string; role: Role; permissions: string[]; tenantId?: string }, expiresIn?: string): string;
}

AuthConfig

PropertyTypeDefaultDescription
jwtSecretstringHS256 signing secret (min 32 chars)
apiKeyHeaderstringX-API-KeyHeader name for API key
apiKeysMap<string, { userId: string; permissions: string[]; tenantId?: string }>Valid API keys with metadata
requireAuthbooleanfalseReject unauthenticated requests when true

AuthContext

typescript
interface AuthContext {
  user?: User;
  authenticated: boolean;
  permissions: string[];
  tenantId?: string;
}
 
interface User {
  id: string;
  email: string;
  role: Role;
  permissions: string[];
  tenantId?: string;
}

Roles and Permissions

RolePermissions
adminAll permissions
operatorpipeline:run, pipeline:define, pipeline:resume, artifact:read, artifact:write, cost:read
viewerpipeline:run, artifact:read, cost:read

Permission Constants

typescript
import { Permissions } from "@reaatech/media-pipeline-mcp-security";
 
Permissions.PIPELINE_RUN;       // "pipeline:run"
Permissions.PIPELINE_DEFINE;    // "pipeline:define"
Permissions.PIPELINE_RESUME;    // "pipeline:resume"
Permissions.ARTIFACT_READ;      // "artifact:read"
Permissions.ARTIFACT_WRITE;     // "artifact:write"
Permissions.ARTIFACT_DELETE;    // "artifact:delete"
Permissions.PROVIDER_MANAGE;    // "provider:manage"
Permissions.COST_READ;          // "cost:read"
Permissions.ADMIN_USERS;        // "admin:users"
Permissions.ADMIN_CONFIG;       // "admin:config"

Operation-to-Permission Mapping

canPerformOperation maps 30+ media operations to required permissions:

OperationRequired Permission
image.generate, image.upscale, audio.tts, video.generate, document.ocr, …pipeline:run
media.pipeline.runpipeline:run
media.pipeline.definepipeline:define
media.pipeline.resumepipeline:resume
media.artifact.get, media.artifact.listartifact:read
media.artifact.deleteartifact:delete
media.providers.listprovider:manage
media.costs.summarycost:read

RateLimiter

Token bucket rate limiter with per-client and per-operation limits.

typescript
class RateLimiter {
  constructor(config: RateLimitConfig);
 
  checkLimit(clientId: string, operation?: string): RateLimitResult;
  getHeaders(result: RateLimitResult): Record<string, string>;
  cleanup(maxAge?: number): void;
}

RateLimitConfig

PropertyTypeDefaultDescription
clientRequestsPerMinutenumberrequiredRPM per client
clientBurstSizenumberrequiredBurst capacity per client
operationLimitsMap<string, { requestsPerMinute: number; burstSize: number }>Per-operation RPM/burst overrides
globalRequestsPerSecondnumberGlobal rate cap across all clients

RateLimitResult

typescript
interface RateLimitResult {
  allowed: boolean;
  remaining: number;
  resetAt: number;       // Unix ms
  retryAfter?: number;   // Ms to wait before retry
}

Response Headers

code
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1714512000
Retry-After: 15

AuditLogger

Immutable audit trail with SIEM export and local backup.

typescript
class AuditLogger {
  constructor(config: AuditExportConfig);
 
  log(event: Omit<AuditEvent, "id" | "timestamp">): void;
 
  // Convenience methods
  logAuthentication(userId: string, email: string, success: boolean, ipAddress?: string): void;
  logAuthorizationFailure(userId: string, operation: string, permission: string): void;
  logPipelineExecution(userId: string, pipelineId: string, success: boolean, duration_ms: number, cost_usd: number, tenantId?: string): void;
  logArtifactAccess(userId: string, artifactId: string, action: "read" | "create" | "delete", success: boolean): void;
  logRateLimitExceeded(clientId: string, operation?: string): void;
 
  destroy(): void;
}

AuditExportConfig

PropertyTypeDefaultDescription
bufferSizenumberrequiredEvents buffered before flush
flushIntervalnumberrequiredMax ms between flushes
retentionDaysnumberrequiredConfig retention (used by cleanup)
splunkEndpointstringSplunk HEC collector URL
splunkTokenstringSplunk HEC token
datadogEndpointstringDatadog Logs API endpoint
datadogApiKeystringDatadog API key
sumoLogicEndpointstringSumo Logic HTTP collector URL
sumoLogicSourceNamestringSumo Logic source name

Audit Event Types

Event TypeDescription
authenticationUser login attempt (success or failure)
authorizationPermission check failure
pipeline.executePipeline execution
pipeline.definePipeline definition creation
pipeline.resumePipeline resume operation
artifact.createArtifact stored
artifact.readArtifact retrieved
artifact.deleteArtifact removed
provider.healthProvider health check result
config.changeConfiguration modification
user.createUser account created
user.deleteUser account deleted
rate_limit.exceededRate limit hit

AuditEvent Structure

typescript
interface AuditEvent {
  id: string;
  timestamp: string;          // ISO 8601
  eventType: AuditEventType;
  actor: {
    userId: string;
    email: string;
    role: string;
    ipAddress?: string;
    userAgent?: string;
  };
  action: {
    operation: string;
    resourceType: string;
    resourceId?: string;
    parameters?: Record<string, unknown>;
  };
  outcome: {
    success: boolean;
    errorCode?: string;
    errorMessage?: string;
    duration_ms: number;
  };
  context: {
    pipelineId?: string;
    artifactId?: string;
    cost_usd?: number;
    tenantId?: string;
    sessionId?: string;
  };
  metadata: Record<string, unknown>;
}

Factory Functions

typescript
function createRBACMiddleware(config: AuthConfig): AuthMiddleware;
function createRateLimiter(config: RateLimitConfig): RateLimiter;
function createAuditLogger(config: AuditExportConfig): AuditLogger;

Usage Patterns

JWT Authentication with Role-Based Access

typescript
const auth = createRBACMiddleware({
  jwtSecret: process.env.JWT_SECRET!,   // Must be ≥32 characters
  requireAuth: true,
});
 
// Generate a token for an operator
const token = auth.generateToken({
  id: "user-123",
  email: "ops@example.com",
  role: "operator",
  permissions: [...],  // auto-populated from role
  tenantId: "tenant-a",
}, "12h");
 
// Authenticate an incoming request
const ctx = await auth.authenticate({
  authorization: `Bearer ${token}`,
});
 
// Check operation access
if (!auth.canPerformOperation(ctx, "media.pipeline.run")) {
  throw new Error("Forbidden");
}

API Key Authentication with Time-Safe Comparison

typescript
const auth = createRBACMiddleware({
  apiKeys: new Map([
    ["sk-prod-abc", { userId: "production-worker", permissions: Object.values(Permissions) }],
    ["sk-staging-xyz", { userId: "staging-worker", permissions: ["pipeline:run", "artifact:read"] }],
  ]),
  apiKeyHeader: "x-api-key",
  requireAuth: true,
});
 
// Constant-time comparison prevents timing attacks
const ctx = await auth.authenticate({ "x-api-key": "sk-prod-abc" });

Per-Operation Rate Limiting

typescript
const limiter = createRateLimiter({
  clientRequestsPerMinute: 100,
  clientBurstSize: 20,
  operationLimits: new Map([
    ["image.generate", { requestsPerMinute: 10, burstSize: 3 }],
    ["video.generate", { requestsPerMinute: 5, burstSize: 1 }],
  ]),
  globalRequestsPerSecond: 50,
});
 
// In request handler:
const result = limiter.checkLimit(clientId, operation);
if (!result.allowed) {
  const headers = limiter.getHeaders(result);
  return { status: 429, headers, body: { error: "Rate limited" } };
}
 
// Periodic cleanup (e.g., every hour)
setInterval(() => limiter.cleanup(3600000), 3600000);

SIEM Export with Local Backup

typescript
const logger = createAuditLogger({
  bufferSize: 50,
  flushInterval: 10000,
  retentionDays: 90,
  splunkEndpoint: "https://splunk.example.com:8088",
  splunkToken: process.env.SPLUNK_HEC_TOKEN!,
  datadogEndpoint: "https://http-intake.logs.datadoghq.com",
  datadogApiKey: process.env.DD_API_KEY!,
});
 
// Log pipeline execution
logger.logPipelineExecution("user-1", "pipeline-abc", true, 4500, 0.035, "tenant-a");
 
// Log artifact access
logger.logArtifactAccess("user-1", "artifact-456", "read", true);
 
// Log rate limit hit
logger.logRateLimitExceeded("client-789", "image.generate");
 
// On shutdown: flush and clean up
process.on("SIGTERM", () => {
  logger.destroy();  // Flush remaining events, clear timers
});

Full Security Middleware Stack

typescript
// Combine all three for a complete request pipeline
const auth = createRBACMiddleware({ jwtSecret: "...", requireAuth: true });
const limiter = createRateLimiter({ clientRequestsPerMinute: 60, clientBurstSize: 10 });
const audit = createAuditLogger({ bufferSize: 100, flushInterval: 5000, retentionDays: 30 });
 
async function handleRequest(req: Request, operation: string) {
  const clientId = req.headers["x-client-id"] ?? "anonymous";
 
  // 1. Rate limit check
  const limitResult = limiter.checkLimit(clientId, operation);
  if (!limitResult.allowed) {
    audit.logRateLimitExceeded(clientId, operation);
    return { status: 429, headers: limiter.getHeaders(limitResult) };
  }
 
  // 2. Authenticate
  const ctx = await auth.authenticate(req.headers);
  if (!ctx.authenticated) {
    audit.logAuthentication(clientId, "unknown", false);
    return { status: 401 };
  }
 
  // 3. Authorize
  if (!auth.canPerformOperation(ctx, operation)) {
    audit.logAuthorizationFailure(ctx.user!.id, operation, "pipeline:run");
    return { status: 403 };
  }
 
  // 4. Execute with audit
  const start = Date.now();
  try {
    const result = await executeOperation(operation);
    audit.logPipelineExecution(ctx.user!.id, "run-123", true, Date.now() - start, 0.007);
    return { status: 200, body: result };
  } catch (err) {
    audit.logPipelineExecution(ctx.user!.id, "run-123", false, Date.now() - start, 0);
    return { status: 500 };
  }
}

License

MIT