Auth & Rate Limiting
API key management, JWT sessions, audit logging, IP filtering, and multi-backend rate limiting for production deployments.
Nella includes a complete authentication and rate limiting system for production deployments. Manage API keys, issue JWT tokens, audit every action, filter by IP, and enforce rate limits with multiple storage backends.
Authentication
API Key Management
Create, validate, rotate, and revoke API keys with granular permissions.
import { Authenticator } from '@getnella/mcp';
const auth = await Authenticator.create({
storagePath: '.nella/auth',
encryptionKey: process.env.NELLA_AUTH_ENCRYPTION_KEY,
});
// Set up a workspace with default keys
const { agent, agentKey, adminKey } = await auth.setupWorkspace('my-workspace');
// Authenticate a request
const result = await auth.authenticate({
apiKey: 'nella_key_...',
action: 'search',
origin: 'cursor',
});
if (result.success) {
// Proceed with the request
}
Permissions
Each API key has granular permissions:
| Permission | Description |
|---|---|
search | Search the indexed codebase |
verify | Verify generated code |
index | Trigger workspace indexing |
readContext | Read session context |
writeContext | Modify session context |
manageSessions | Create/delete sessions |
admin | Full access including key management |
Supported Agent Types
Keys can be scoped to specific agent types: copilot, cursor, cline, aider, continue, or custom.
Key Encryption
API keys are encrypted at rest using AES-256-GCM with a 12-byte IV and 16-byte authentication tag. Set the encryption key via the NELLA_AUTH_ENCRYPTION_KEY environment variable (must be 32 bytes).
Key Rotation
Automatic key rotation is supported via rotation policies. When a key is rotated, the old key remains valid for a grace period before revocation.
JWT Sessions
Issue short-lived JWT tokens for session-based authentication.
import { TokenManager } from '@getnella/mcp';
const tokens = new TokenManager({
secret: process.env.NELLA_JWT_SECRET,
});
// Issue a token from a valid API key
const { token, expiresAt } = tokens.issueToken(apiKey, {
sessionId: 'sess_123',
});
// Issue a short-lived token (default: 5 minutes)
const shortToken = tokens.issueShortLivedToken(apiKey, 300);
// Validate
const validation = tokens.validateToken(token);
if (validation.valid) {
console.log(validation.payload.permissions);
}
JWT payload includes: subject (key ID), issuer, audience, expiry, workspace ID, agent ID, permissions, and session info.
Validation error codes: INVALID_TOKEN, EXPIRED_TOKEN, REVOKED_TOKEN, INVALID_SIGNATURE.
Set the signing secret via NELLA_JWT_SECRET environment variable.
Audit Logging
Every authentication and authorization event is logged to an append-only audit log with automatic file rotation.
import { AuditLogManager } from '@getnella/mcp';
const audit = await AuditLogManager.create({
storagePath: '.nella/audit',
});
// Logs are written automatically by the Authenticator
// You can also log manually:
await audit.logAuth(true, 'agent-1', 'search', { query: 'handleAuth' });
await audit.logKeyOp('create', 'admin', 'key_abc', 'Agent Key');
Log Categories
| Category | Actions |
|---|---|
authentication | Login, validate, reject |
authorization | Permission check, file access |
key_management | Create, rotate, revoke, expire |
IP Filtering
Restrict access by IP address with CIDR range support.
import { IPFilter } from '@getnella/mcp';
const filter = new IPFilter({
allowedIPs: ['10.0.0.0/8', '192.168.1.0/24'],
enabled: true,
});
const result = filter.isAllowed('10.0.1.50');
// { allowed: true }
// Also supports X-Forwarded-For chains
const chainResult = filter.isAllowedChain(['203.0.113.1', '10.0.1.50']);
Rate Limiting
Enforce request rate limits with multiple algorithms and storage backends.
Quick Start
import { RateLimiter } from '@getnella/mcp';
const limiter = new RateLimiter({
requestsPerMinute: 60,
requestsPerHour: 1000,
requestsPerDay: 10000,
maxTokensPerRequest: 100000,
maxConcurrent: 5,
});
// Check without consuming
const check = limiter.check({ entityId: 'agent-1', action: 'search' });
// Check and consume
const result = limiter.consume({ entityId: 'agent-1', action: 'search' });
if (!result.allowed) {
// result.retryAfter tells the client when to retry
}
Algorithms
| Algorithm | Description |
|---|---|
sliding-window (default) | Tracks requests in minute/hour/day windows |
token-bucket | Configurable refill rate and bucket size |
Storage Backends
| Backend | Description |
|---|---|
memory (default) | In-process Map — fast, resets on restart |
redis | Redis with TLS, Sentinel, and Cluster support |
sqlite | Persistent SQLite database |
auto | Tries Redis → SQLite → memory |
Priority Levels
| Level | Multiplier | Behavior |
|---|---|---|
critical | Bypass | Exempt from rate limits |
high | 2.0x | Double the allowed rate |
normal | 1.0x | Default limits |
low | 0.5x | Half the allowed rate |
Dynamic Limits
Rate limits can adjust automatically based on system load:
{
dynamicLimits: {
enabled: true,
loadFunction: () => getCurrentCPUUsage(), // returns 0-1
minMultiplier: 0.5, // reduce to 50% under load
maxMultiplier: 1.5, // increase to 150% when idle
evaluationInterval: 30000 // check every 30 seconds
}
}
Graceful Degradation
When gracefulDegradation is configured, a warning event is emitted when usage hits the soft limit threshold (default: 80%) before hard blocking occurs. This gives clients time to back off.
HTTP Headers
Rate limit responses include standard headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1706140800
X-RateLimit-Policy: sliding-window
Retry-After: 30