@axxify/auth
v1.0.0
Published
Authentication and authorization for AgentOS - JWT, API Keys, RBAC, Audit Logging
Maintainers
Readme
@agentos/auth
Authentication, authorization, and audit logging for AgentOS.
Features
- JWT Management - Sign, verify, and refresh JSON Web Tokens
- API Key Management - Create, validate, revoke, and rotate API keys
- RBAC - Role-based access control with policies and permissions
- Audit Logging - Comprehensive event logging for compliance
- Middleware - Fastify middleware for request authentication
Installation
npm install @agentos/authQuick Start
import {
createJWTManager,
createAPIKeyManager,
createRBACService,
createAuditLogger,
InMemoryAPIKeyStore,
InMemoryRoleStore,
InMemoryPolicyStore,
} from '@agentos/auth';
// Initialize JWT Manager
const jwtManager = createJWTManager({
secret: process.env.JWT_SECRET,
issuer: 'my-app',
defaultExpiresIn: '15m',
});
// Create a token
const token = await jwtManager.sign({
sub: 'user-123',
email: '[email protected]',
roles: ['user'],
});
// Verify a token
const payload = await jwtManager.verify(token);
// Initialize API Key Manager
const apiKeyManager = createAPIKeyManager({
store: new InMemoryAPIKeyStore(),
});
// Create an API key
const apiKey = await apiKeyManager.create({
name: 'Production Key',
prefix: 'sk_live',
scope: 'read',
});
// Initialize RBAC
const rbacService = createRBACService({
roleStore: new InMemoryRoleStore(),
policyStore: new InMemoryPolicyStore(),
});
// Check permissions
const result = rbacService.evaluate({
userId: 'user-123',
userRoles: ['role:user'],
userPermissions: [],
resource: 'agent',
action: 'execute',
});
// Initialize Audit Logger
const auditLogger = createAuditLogger({
store: new InMemoryAuditStore(),
syncWrites: true,
});
// Log an event
await auditLogger.log({
type: 'auth.login',
severity: 'info',
actor: { id: 'user-123', type: 'user' },
action: { resource: 'session', operation: 'login' },
outcome: { success: true },
context: { userId: 'user-123' },
});JWT Management
Creating a JWT Manager
import { createJWTManager } from '@agentos/auth';
const jwtManager = createJWTManager({
secret: 'your-32-byte-secret-key',
issuer: 'your-app-name',
audience: 'your-client-id', // optional
defaultExpiresIn: '1h',
algorithm: 'ES256',
});Signing Tokens
// Basic token
const token = await jwtManager.sign({
sub: 'user-id',
email: '[email protected]',
});
// Token with custom expiration
const shortToken = await jwtManager.sign(
{ sub: 'temp-token' },
'5m' // expires in 5 minutes
);Verifying Tokens
try {
const payload = await jwtManager.verify(token);
console.log('User:', payload.sub);
} catch (error) {
console.log('Invalid token:', error.message);
}Refreshing Tokens
const newToken = await jwtManager.refresh(oldToken);API Key Management
Creating Keys
const apiKey = await apiKeyManager.create({
name: 'API Key Name',
prefix: 'sk_live', // sk_live, sk_test, sk_dev, ak_live, ak_test, ak_dev
scope: 'read', // read, write, admin
userId: 'user-123',
expiresAt: new Date('2025-12-31'),
metadata: { team: 'engineering' },
});
// Store this secret securely - it's only shown once!
console.log(apiKey.secret); // e.g., sk_live_a1b2c3...Validating Keys
const key = await apiKeyManager.validate('sk_live_abc123...');
if (key) {
console.log('Valid key for:', key.name);
}Revoking Keys
await apiKeyManager.revoke(keyId);RBAC
Default Roles
The package includes three default roles:
ADMIN_ROLE- Full access to all resourcesUSER_ROLE- Standard user accessGUEST_ROLE- Read-only access
Creating Custom Roles
const role = await rbacService.createRole({
name: 'Data Analyst',
description: 'Can read agents and projects',
permissions: [
{ id: 'p:agent:read', resource: 'agent', action: 'read' },
{ id: 'p:project:read', resource: 'project', action: 'read' },
],
isSystem: false,
});Evaluating Access
const result = rbacService.evaluate({
userId: 'user-123',
userRoles: ['role:user'],
userPermissions: [],
resource: 'agent',
action: 'execute',
});
if (result.allowed) {
// Proceed with action
} else {
console.log('Access denied:', result.reason);
}Conditional Permissions
const role = await rbacService.createRole({
name: 'Project Owner',
permissions: [{
id: 'p:project:manage',
resource: 'project',
action: 'manage',
conditions: [
{ field: 'ownerId', operator: 'eq', value: '${userId}' },
],
}],
});Audit Logging
Basic Usage
await auditLogger.log({
type: 'auth.login',
severity: 'info',
actor: { id: 'user-123', type: 'user', email: '[email protected]' },
action: { resource: 'session', operation: 'login' },
outcome: { success: true },
context: {
userId: 'user-123',
ipAddress: '192.168.1.1',
userAgent: 'Mozilla/5.0...',
requestId: 'req-123',
},
});Querying Events
const result = await auditLogger.query({
types: ['auth.login', 'auth.logout'],
userId: 'user-123',
startTime: new Date('2024-01-01'),
endTime: new Date('2024-01-31'),
limit: 50,
});
console.log(`Found ${result.total} events`);
for (const event of result.events) {
console.log(event.timestamp, event.type);
}Scoped Logger
const scoped = auditLogger.withContext({
userId: 'user-123',
organizationId: 'org-456',
});
await scoped.logLogin('user-123', true);
await scoped.logPermissionCheck('user-123', 'agent', 'execute', true);Compliance Export
const csv = await auditLogger.export({
startTime: new Date('2024-01-01'),
endTime: new Date('2024-01-31'),
}, 'csv');
// Save to file or send to compliance systemFastify Middleware
Setting Up Middleware
import Fastify from 'fastify';
import { createAuthMiddleware } from '@agentos/auth';
const app = Fastify();
await createAuthMiddleware(app, {
jwtSecret: process.env.JWT_SECRET,
jwtIssuer: 'my-app',
jwtAudience: 'my-client',
rbacService,
auditLogger,
publicPaths: ['/health', '/metrics', '/public'],
recordAudit: true,
});Accessing User in Routes
app.get('/profile', async (request, reply) => {
const user = request.user;
if (!user) {
return reply.status(401).send({ error: 'Unauthorized' });
}
return {
id: user.userId,
email: user.email,
roles: user.roles,
};
});Types
JWT Payload
interface JWTPayload {
sub?: string; // Subject (user ID)
email?: string; // User email
roles?: string[]; // User roles
permissions?: string[];
iat?: number; // Issued at
exp?: number; // Expiration
iss?: string; // Issuer
aud?: string | string[]; // Audience
}Permission
interface Permission {
id: string;
resource: Resource;
action: Action;
conditions?: PermissionCondition[];
}
type Resource = 'user' | 'agent' | 'project' | 'workspace' | 'api_key' | 'role' | 'audit_log' | 'settings' | 'billing' | 'webhook';
type Action = 'create' | 'read' | 'update' | 'delete' | 'list' | 'manage' | 'execute' | 'admin';Audit Event
interface AuditEvent {
id: string;
timestamp: string;
type: AuditEventType;
severity: 'debug' | 'info' | 'warning' | 'error' | 'critical';
actor: { id?: string; type: 'user' | 'service' | 'system' | 'api_key'; email?: string };
action: { resource: string; resourceId?: string; operation: string };
outcome: { success: boolean; code?: string; description?: string };
context: AuditContext;
}Storage Interfaces
For production use, implement these interfaces for your storage backend:
APIKeyStore
interface APIKeyStore {
save(key: APIKey): Promise<void>;
findById(id: string): Promise<APIKey | null>;
findByHash(hash: string): Promise<APIKey | null>;
findByUserId(userId: string): Promise<APIKey[]>;
update(key: APIKey): Promise<void>;
delete(id: string): Promise<void>;
}AuditStore
interface AuditStore {
save(event: AuditEvent): Promise<void>;
saveBatch(events: AuditEvent[]): Promise<void>;
findById(id: string): Promise<AuditEvent | null>;
find(query: AuditEventQuery): Promise<{ events: AuditEvent[]; total: number }>;
deleteOlderThan(date: Date): Promise<number>;
}License
MIT
