Authentication Module
The SDK includes authentication utilities for building services that consume the NIL Taxonomy.
Overview
The auth module provides:
- API Key validation - Verify and authenticate API keys
- JWT verification - Validate JSON Web Tokens
- Middleware helpers - Easy integration with web frameworks
Basic Usage
import {
AuthManager,
JWTAuthAdapter,
APIKeyAuthAdapter
} from '@nil-taxonomy/sdk/auth';
// Create auth manager with multiple strategies
const authManager = new AuthManager([
new JWTAuthAdapter({ secret: process.env.JWT_SECRET! }),
new APIKeyAuthAdapter({ lookup: lookupKeyInDB }),
]);API Key Authentication
Setup
import { APIKeyAuthAdapter } from '@nil-taxonomy/sdk/auth';
// Define key lookup function
async function lookupKeyInDB(keyHash: string) {
const key = await db.apiKeys.findOne({
where: { key_hash: keyHash, status: 'active' }
});
return key ? {
userId: key.user_id,
scopes: key.scopes,
tier: key.tier
} : null;
}
const adapter = new APIKeyAuthAdapter({
lookup: lookupKeyInDB
});Authenticate Requests
const request = new Request('https://example.com/api/data', {
headers: {
'Authorization': 'Bearer nilk_xxxxx'
}
});
const result = await adapter.authenticate(request);
if (result.authenticated) {
console.log('User ID:', result.userId);
console.log('Scopes:', result.scopes);
} else {
console.error('Authentication failed');
}JWT Authentication
Setup
import { JWTAuthAdapter } from '@nil-taxonomy/sdk/auth';
const adapter = new JWTAuthAdapter({
secret: process.env.JWT_SECRET!,
algorithms: ['HS256'], // Supported algorithms
issuer: 'your-service',
audience: 'your-api'
});Verify Tokens
const request = new Request('https://example.com/api/data', {
headers: {
'Authorization': 'Bearer eyJhbGci...'
}
});
const result = await adapter.authenticate(request);
if (result.authenticated) {
console.log('User ID:', result.userId);
console.log('JWT Claims:', result.claims);
}Multi-Strategy Auth
Use multiple authentication methods:
import { AuthManager } from '@nil-taxonomy/sdk/auth';
const authManager = new AuthManager([
new JWTAuthAdapter({ secret: process.env.JWT_SECRET! }),
new APIKeyAuthAdapter({ lookup: lookupKeyInDB }),
]);
// Try all strategies until one succeeds
const result = await authManager.authenticate(request);
if (!result.authenticated) {
return new Response('Unauthorized', { status: 401 });
}Middleware Integration
Next.js API Routes
import { createAuthMiddleware } from '@nil-taxonomy/sdk/auth';
const auth = createAuthMiddleware(authManager);
export async function GET(request: Request) {
// Require authentication
const user = await auth.requireAuth(request);
// User is authenticated
return Response.json({ userId: user.userId });
}Require Specific Scopes
export async function POST(request: Request) {
// Require specific scope
const user = await auth.requireScope(request, 'taxonomy:write');
// User has required scope
return Response.json({ success: true });
}Optional Authentication
export async function GET(request: Request) {
// Optional auth (doesn't throw)
const user = await auth.optionalAuth(request);
if (user) {
// Authenticated user
return Response.json({ data: privateData });
} else {
// Anonymous user
return Response.json({ data: publicData });
}
}Scopes
Define granular permissions:
const scopes = {
'taxonomy:read': 'Read taxonomy data',
'taxonomy:write': 'Modify taxonomy data',
'licenses:create': 'Create licenses',
'licenses:read': 'View licenses',
};
// Check if user has scope
if (user.scopes.includes('taxonomy:write')) {
// Allow modification
}Custom Adapters
Create custom authentication adapters:
import { AuthAdapter, AuthResult } from '@nil-taxonomy/sdk/auth';
class CustomAdapter implements AuthAdapter {
async authenticate(request: Request): Promise<AuthResult> {
// Your custom logic
const token = this.extractToken(request);
const user = await this.verifyToken(token);
if (user) {
return {
authenticated: true,
userId: user.id,
scopes: user.scopes
};
}
return { authenticated: false };
}
private extractToken(request: Request): string | null {
// Extract token from request
return null;
}
private async verifyToken(token: string) {
// Verify token
return null;
}
}Security Best Practices
1. Use Secure Secrets
// ✅ Good: Environment variables
const secret = process.env.JWT_SECRET;
// ❌ Bad: Hardcoded
const secret = 'my-secret-key';2. Hash API Keys
Never store API keys in plain text:
import { createHash } from 'crypto';
// Hash before storing
const keyHash = createHash('sha256')
.update(apiKey)
.digest('hex');
await db.apiKeys.create({
key_hash: keyHash, // Store hash, not plain key
user_id: userId
});3. Validate Algorithms
Restrict JWT algorithms:
const adapter = new JWTAuthAdapter({
secret: process.env.JWT_SECRET!,
algorithms: ['HS256'], // Only allow HS256
});4. Check Expiration
Ensure tokens have expiration:
const payload = {
userId: '123',
exp: Math.floor(Date.now() / 1000) + (60 * 60) // 1 hour
};