npm package: @kitiumai/auth-mongodb
Description: MongoDB storage adapter for Kitium Auth
Author: KitiumAI
Latest version: 1.0.1

# @kitiumai/auth-mongodb

MongoDB storage adapter for Kitium Auth - production-ready persistence layer with automatic indexing and atomic operations.

## Installation

```bash
npm install @kitiumai/auth @kitiumai/auth-mongodb mongodb
```

## Quick Start

```typescript
import { AuthCore, defineConfig, createEmailProvider, createOAuthProvider } from '@kitiumai/auth'
import { MongoDBStorageAdapter } from '@kitiumai/auth-mongodb'

// Create MongoDB adapter
const adapter = new MongoDBStorageAdapter(
  process.env.MONGODB_URI!,
  { dbName: 'kitium-auth' }
)

// Define auth configuration
const config = defineConfig({
  appUrl: process.env.NEXT_PUBLIC_APP_URL!,
  providers: [
    createEmailProvider({
      id: 'email',
      from: process.env.EMAIL_FROM!
    }),
    createOAuthProvider({
      id: 'google',
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!
    })
  ],
  storage: { driver: 'mongodb', url: process.env.MONGODB_URI! },
  apiKeys: { prefix: 'kit_', hash: { algo: 'argon2id' } },
  sessions: { cookieName: 'auth_token', ttlSeconds: 604800 }
})

// Create auth instance
const auth = new AuthCore(adapter, {
  jwtSecret: process.env.JWT_SECRET!,
  providers: config.providers
})

// Connect to MongoDB
await adapter.connect()
```

## Advanced Configuration

### Custom Database Name

```typescript
const adapter = new MongoDBStorageAdapter(
  'mongodb+srv://user:pass@cluster.mongodb.net/',
  { dbName: 'my-app-auth' }
)
```

### Custom Collection Names

```typescript
const adapter = new MongoDBStorageAdapter(
  process.env.MONGODB_URI!,
  {
    dbName: 'kitium-auth',
    collectionNames: {
      users: 'auth_users',
      apiKeys: 'auth_api_keys',
      sessions: 'auth_sessions',
      organizations: 'auth_orgs',
      emailVerificationTokens: 'auth_email_tokens',
      emailTokenAttempts: 'auth_email_attempts',
      authEvents: 'auth_events'
    }
  }
)
```

### MongoDB Connection Options

```typescript
const adapter = new MongoDBStorageAdapter(
  process.env.MONGODB_URI!,
  {
    dbName: 'kitium-auth',
    maxPoolSize: 50,
    minPoolSize: 10,
    maxIdleTimeMS: 30000,
    retryWrites: true,
    retryReads: true,
    serverSelectionTimeoutMS: 5000
  }
)
```

## Features

✅ **Automatic Index Creation**
- Unique indexes on email and OAuth links
- Compound indexes for efficient queries
- TTL indexes for automatic token cleanup

✅ **Atomic Operations**
- Atomic session creation and updates
- Atomic user updates with metadata
- Transaction support (requires MongoDB replica set)

✅ **Efficient Query Patterns**
- Indexed lookups by email, OAuth provider, API key hash
- Batch operations for bulk updates
- Proper use of sparse and unique indexes

✅ **Production Ready**
- Connection pooling with configurable pool size
- Automatic reconnection with exponential backoff
- Proper error handling and logging

## Usage Examples

### Email/Password Authentication

```typescript
import { getEmailAuthRoutes } from '@kitiumai/auth'

const { createRegisterRoute, createLoginRoute, createForgotPasswordRoute, createResetPasswordRoute } = await getEmailAuthRoutes()

const emailConfig: EmailAuthRoutesConfig = {
  appUrl: 'https://example.com',
  emailProvider: yourEmailProvider,
  minNameLength: 2,
  maxNameLength: 255,
  sessionTtlSeconds: 7 * 24 * 60 * 60,  // 7 days
  passwordResetTokenTtlSeconds: 60 * 60, // 1 hour
  passwordResetTokenLength: 32
}

// Use in Next.js API routes
export const POST = createRegisterRoute(adapter, emailConfig)
```

### Password Validation

```typescript
import { validatePasswordStrength, validateEmail, normalizeEmail } from '@kitiumai/auth'

// With custom rules
const result = validatePasswordStrength('MyPassword123!', {
  minLength: 12,
  maxLength: 64,
  requireSpecialChars: true,
  specialCharsPattern: '!@#$%^&*'
})

if (!result.valid) {
  console.log(result.errors) // ['Password must be at least 12 characters...']
}

// Email validation
const email = normalizeEmail(userInput)
if (validateEmail(email)) {
  // Valid email
}
```

### Password Hashing

```typescript
import { hashPassword, verifyPassword } from '@kitiumai/auth'

// Hash with default settings
const hash = await hashPassword('userPassword123')

// Hash with custom settings
const customHash = await hashPassword('userPassword123', {
  timeCost: 4,
  memory: 131072,  // 128MB
  parallelism: 8,
  type: 'argon2id'
})

// Verify password
const isValid = await verifyPassword('userPassword123', hash)
```

### Email Templates

```typescript
import { getEmailTemplates } from '@kitiumai/auth'

const {
  createPasswordResetTemplate,
  createEmailVerificationTemplate,
  createVerificationCodeTemplate,
  createLoginLinkTemplate,
  createWelcomeTemplate
} = await getEmailTemplates()

// Create customized password reset email
const emailTemplate = createPasswordResetTemplate(
  'https://example.com/reset?token=abc123',
  {
    appName: 'My App',
    userName: 'John Doe',
    expiresIn: '24 hours',
    supportEmail: 'support@myapp.com'
  }
)

// Use template
await emailProvider.sendMail({
  to: 'user@example.com',
  subject: emailTemplate.subject,
  html: emailTemplate.html,
  text: emailTemplate.text
})
```

## Environment Variables

```env
# Database
MONGODB_URI=mongodb+srv://user:pass@cluster.mongodb.net/
MONGODB_DB_NAME=kitium-auth

# Auth
JWT_SECRET=your-secret-key-here
NEXT_PUBLIC_APP_URL=https://example.com

# Email
EMAIL_FROM=noreply@example.com
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password

# OAuth (Google)
NEXT_PUBLIC_GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=xxx

# Optional
MONGODB_MAX_POOL_SIZE=50
MONGODB_RETRY_WRITES=true
```

## Configuration Reference

### MongoDBAdapterOptions

```typescript
interface MongoDBAdapterOptions {
  // Database name (default: 'kitium-auth')
  dbName?: string

  // Custom collection names
  collectionNames?: {
    users?: string
    apiKeys?: string
    sessions?: string
    organizations?: string
    emailVerificationTokens?: string
    emailTokenAttempts?: string
    authEvents?: string
  }

  // MongoDB driver options
  maxPoolSize?: number
  minPoolSize?: number
  maxIdleTimeMS?: number
  retryWrites?: boolean
  retryReads?: boolean
  [key: string]: any
}
```

### EmailAuthRoutesConfig

```typescript
interface EmailAuthRoutesConfig {
  // Required
  appUrl: string
  emailProvider: IEmailProvider

  // Optional
  loginRedirect?: string
  registerRedirect?: string
  minNameLength?: number              // Default: 2
  maxNameLength?: number              // Default: 255
  sessionTtlSeconds?: number          // Default: 7 days
  passwordResetTokenTtlSeconds?: number // Default: 1 hour
  passwordResetTokenLength?: number   // Default: 32
}
```

### PasswordValidationRules

```typescript
interface PasswordValidationRules {
  minLength?: number                  // Default: 8
  maxLength?: number                  // Default: 128
  requireLowercase?: boolean          // Default: true
  requireUppercase?: boolean          // Default: true
  requireNumbers?: boolean            // Default: true
  requireSpecialChars?: boolean       // Default: true
  specialCharsPattern?: string        // Default: '!@#$%^&*...'
}
```

## API Reference

### MongoDBStorageAdapter

Implements the `StorageAdapter` interface with the following methods:

**Connection:**
- `connect(): Promise<void>` - Connect to MongoDB
- `disconnect(): Promise<void>` - Disconnect from MongoDB

**Users:**
- `createUser(data: CreateUserInput): Promise<UserRecord>`
- `getUser(id: string): Promise<UserRecord | null>`
- `getUserByEmail(email: string): Promise<UserRecord | null>`
- `getUserByOAuth(provider: string, sub: string): Promise<UserRecord | null>`
- `updateUser(id: string, data: UpdateUserInput): Promise<UserRecord>`
- `deleteUser(id: string): Promise<void>`
- `linkOAuthAccount(userId: string, provider: string, oauthLink: OAuthLink): Promise<UserRecord>`

**Sessions:**
- `createSession(data: Omit<SessionRecord, 'id' | 'createdAt'>): Promise<SessionRecord>`
- `getSession(id: string): Promise<SessionRecord | null>`
- `updateSession(id: string, data: Partial<SessionRecord>): Promise<SessionRecord>`
- `deleteSession(id: string): Promise<void>`

**API Keys:**
- `createApiKey(data: Omit<ApiKeyRecord, 'id' | 'createdAt'>): Promise<ApiKeyRecord>`
- `getApiKey(id: string): Promise<ApiKeyRecord | null>`
- `getApiKeyByHash(hash: string): Promise<ApiKeyRecord | null>`
- `getApiKeysByPrefixAndLastFour(prefix: string, lastFour: string): Promise<ApiKeyRecord[]>`
- `updateApiKey(id: string, data: Partial<ApiKeyRecord>): Promise<ApiKeyRecord>`
- `deleteApiKey(id: string): Promise<void>`
- `listApiKeys(principalId: string): Promise<ApiKeyRecord[]>`

**Organizations:**
- `createOrganization(data: Omit<OrganizationRecord, 'id' | 'createdAt' | 'updatedAt'>): Promise<OrganizationRecord>`
- `getOrganization(id: string): Promise<OrganizationRecord | null>`
- `updateOrganization(id: string, data: Partial<OrganizationRecord>): Promise<OrganizationRecord>`
- `deleteOrganization(id: string): Promise<void>`

**Email Verification Tokens:**
- `createEmailVerificationToken(data: Omit<EmailVerificationToken, 'id'>): Promise<EmailVerificationToken>`
- `getEmailVerificationTokens(email: string, type?: string): Promise<EmailVerificationToken[]>`
- `getEmailVerificationTokenById(id: string): Promise<EmailVerificationToken | null>`
- `markEmailVerificationTokenAsUsed(id: string): Promise<EmailVerificationToken>`
- `deleteExpiredEmailVerificationTokens(): Promise<number>`
- `getEmailVerificationTokenAttempts(tokenId: string): Promise<number>`
- `incrementEmailVerificationTokenAttempts(tokenId: string): Promise<number>`

**Events:**
- `emitEvent(event: AuthEvent): Promise<void>`

## Best Practices

1. **Always call `connect()`** before using the adapter
2. **Use connection pooling** for production (configured automatically)
3. **Enable `retryWrites`** for automatic retry on transient failures
4. **Monitor indexes** with MongoDB Atlas or your monitoring tool
5. **Set appropriate TTL** for sessions based on your security needs
6. **Use strong JWT secrets** - minimum 32 bytes of entropy
7. **Validate all inputs** - use provided validation functions
8. **Handle email sending errors gracefully** - async, non-blocking
9. **Implement rate limiting** for authentication endpoints
10. **Log authentication events** for audit trails

## Troubleshooting

### Connection Issues
```typescript
try {
  await adapter.connect()
} catch (error) {
  console.error('Failed to connect to MongoDB:', error)
  // Check connection string, network, credentials
}
```

### Index Errors
MongoDB automatically creates indexes on first connect. If you need to rebuild indexes:
```typescript
await adapter.disconnect()
// Remove old collection in MongoDB
await adapter.connect() // Recreates with fresh indexes
```

### Performance Optimization
For high-traffic applications, tune these settings:
```typescript
const adapter = new MongoDBStorageAdapter(uri, {
  maxPoolSize: 100,
  minPoolSize: 25,
  maxIdleTimeMS: 60000
})
```

## License

MIT