npm package: @kdsp/auth
Description: Shared authentication middleware and models for Kernel services
Author: Kernel Team
Latest version: 1.0.1

# @kdsp/auth

Shared authentication middleware, models, and services for Kernel microservices.

## Installation

```bash
npm install @kdsp/auth
```

## Peer Dependencies

This package requires the following peer dependencies:

```bash
npm install mongoose express
```

## Features

- **JWT Token Service** - Generate, verify, and manage JWT tokens
- **User Model** - Complete user schema with roles, permissions, OAuth support
- **Session Model** - Session management with device tracking and auto-expiry
- **Role Model** - Flexible role-based access control with inheritance
- **Authentication Middleware** - Ready-to-use Express middleware
- **Authorization Middleware** - Role and permission-based access control
- **Error Classes** - Comprehensive error types for auth flows

## Quick Start

### 1. Initialize Models

```typescript
import mongoose from 'mongoose';
import { getUserModel, getSessionModel, getRoleModel } from '@kdsp/auth';

// Connect to MongoDB
await mongoose.connect('mongodb://localhost:27017/myapp');

// Initialize models (creates them if not exists)
const User = getUserModel({ multiTenantEnabled: false });
const Session = getSessionModel({ multiTenantEnabled: false });
const Role = getRoleModel();
```

### 2. Configure Token Service

```typescript
import { createTokenService } from '@kdsp/auth';

const tokenService = createTokenService({
  accessTokenSecret: process.env.JWT_SECRET!,
  accessTokenExpiry: '1h',
  refreshTokenExpiry: '7d',
  issuer: 'my-app',
  audience: 'my-api',
});

// Generate tokens for a user
const tokens = tokenService.generateTokenPair({
  userId: user._id.toString(),
  tenantId: user.tenantId?.toString(),
  roles: user.roles.map(r => r.name),
});
```

### 3. Setup Auth Middleware

```typescript
import express from 'express';
import { createAuthMiddleware, getUserModel, getSessionModel } from '@kdsp/auth';

const app = express();

// Create middleware factory
const auth = createAuthMiddleware({
  tokenService,
  userModel: getUserModel(),
  sessionModel: getSessionModel(),
  validateSession: true, // Check session in DB (optional but recommended)
});

// Protected route
app.get('/api/profile', auth.authenticate, (req, res) => {
  res.json({ user: req.user });
});

// Optional auth (user attached if token valid, but not required)
app.get('/api/public', auth.optionalAuth, (req, res) => {
  res.json({ user: req.user || null });
});

// Role-based authorization
app.delete('/api/users/:id', 
  auth.authenticate, 
  auth.authorize('admin', 'superadmin'),
  (req, res) => {
    // Only admins can delete users
  }
);

// Permission-based authorization
app.post('/api/articles',
  auth.authenticate,
  auth.requirePermission('articles.create'),
  (req, res) => {
    // User must have 'articles.create' permission
  }
);

// Resource ownership (user can only access own resources)
app.get('/api/users/:userId/settings',
  auth.authenticate,
  auth.requireOwnership('userId'),
  (req, res) => {
    // User can only access their own settings (admins bypass)
  }
);
```

### 4. Custom Logger

```typescript
import winston from 'winston';

const logger = winston.createLogger({ /* ... */ });

const auth = createAuthMiddleware({
  tokenService,
  userModel: getUserModel(),
  sessionModel: getSessionModel(),
  logger: {
    debug: (msg, ...args) => logger.debug(msg, ...args),
    info: (msg, ...args) => logger.info(msg, ...args),
    warn: (msg, ...args) => logger.warn(msg, ...args),
    error: (msg, ...args) => logger.error(msg, ...args),
  },
});
```

## API Reference

### Models

#### User Model

```typescript
import { getUserModel, createUserModel, UserSchemaOptions } from '@kdsp/auth';

// Get existing model or create new one
const User = getUserModel(options?: UserSchemaOptions);

// Force create new model (useful in tests)
const User = createUserModel(options?: UserSchemaOptions);

interface UserSchemaOptions {
  multiTenantEnabled?: boolean;  // Default: false
  maxLoginAttempts?: number;     // Default: 5
  lockoutDurationMs?: number;    // Default: 15 minutes
}
```

#### Session Model

```typescript
import { getSessionModel, createSessionModel, SessionSchemaOptions } from '@kdsp/auth';

const Session = getSessionModel(options?: SessionSchemaOptions);

interface SessionSchemaOptions {
  multiTenantEnabled?: boolean;  // Default: false
}
```

#### Role Model

```typescript
import { getRoleModel, createRoleModel } from '@kdsp/auth';

const Role = getRoleModel();
```

### Token Service

```typescript
import { createTokenService, TokenServiceConfig } from '@kdsp/auth';

const tokenService = createTokenService(config: TokenServiceConfig);

interface TokenServiceConfig {
  accessTokenSecret: string;      // Required
  accessTokenExpiry?: string;     // Default: '1h'
  refreshTokenExpiry?: string;    // Default: '7d'
  issuer?: string;                // Default: 'kernel-auth'
  audience?: string;              // Default: 'kernel-api'
}

// Methods
tokenService.generateAccessToken(payload);
tokenService.generateRefreshToken();
tokenService.generateTokenPair(user);
tokenService.verifyAccessToken(token);
tokenService.decodeToken(token);
tokenService.generateVerificationToken();
tokenService.generatePasswordResetToken();
tokenService.hashToken(token);
```

### Middleware

```typescript
import { createAuthMiddleware, AuthMiddlewareConfig } from '@kdsp/auth';

const auth = createAuthMiddleware(config: AuthMiddlewareConfig);

interface AuthMiddlewareConfig {
  tokenService: TokenService;
  userModel: IUserModel;
  sessionModel: ISessionModel;
  logger?: Logger;
  validateSession?: boolean;  // Default: true
}

// Available middleware
auth.authenticate;              // Require valid token
auth.optionalAuth;              // Attach user if token present
auth.authorize(...roles);       // Require specific roles
auth.requirePermission(...perms); // Require specific permissions
auth.requireOwnership(field);   // Ensure resource ownership
```

### Error Classes

```typescript
import {
  AppError,
  BadRequestError,
  UnauthorizedError,
  ForbiddenError,
  NotFoundError,
  ConflictError,
  ValidationError,
  TooManyRequestsError,
  InternalServerError,
  ServiceUnavailableError,
  AuthenticationError,
  TokenExpiredError,
  InvalidTokenError,
  AccountLockedError,
  EmailNotVerifiedError,
  InsufficientPermissionsError,
} from '@kdsp/auth';
```

## Multi-Tenancy

Enable multi-tenant support:

```typescript
const User = getUserModel({ multiTenantEnabled: true });
const Session = getSessionModel({ multiTenantEnabled: true });

// Now tenantId is required on User and Session documents
```

## TypeScript Support

Full TypeScript support with exported types:

```typescript
import type {
  IUser,
  IUserModel,
  ISession,
  ISessionModel,
  IRole,
  IRoleModel,
  TokenPayload,
  TokenPair,
  AuthenticatedRequest,
  AuthenticatedUser,
} from '@kdsp/auth';
```

## Migration from Existing Code

If migrating from existing user-management code:

1. Install the package
2. Replace model imports with `getUserModel()`, etc.
3. Replace middleware imports with `createAuthMiddleware()`
4. Update config to match the new interface

## License

MIT