SDK Guide
Authentication

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
};

Next Steps