@kitiumai/auth-mongodb
v1.0.1
Published
MongoDB storage adapter for Kitium Auth
Maintainers
Readme
@kitiumai/auth-mongodb
MongoDB storage adapter for Kitium Auth - production-ready persistence layer with automatic indexing and atomic operations.
Installation
npm install @kitiumai/auth @kitiumai/auth-mongodb mongodbQuick Start
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
const adapter = new MongoDBStorageAdapter(
'mongodb+srv://user:[email protected]/',
{ dbName: 'my-app-auth' }
)Custom Collection Names
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
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
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
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
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
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: '[email protected]'
}
)
// Use template
await emailProvider.sendMail({
to: '[email protected]',
subject: emailTemplate.subject,
html: emailTemplate.html,
text: emailTemplate.text
})Environment Variables
# Database
MONGODB_URI=mongodb+srv://user:[email protected]/
MONGODB_DB_NAME=kitium-auth
# Auth
JWT_SECRET=your-secret-key-here
NEXT_PUBLIC_APP_URL=https://example.com
# Email
[email protected]
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
[email protected]
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=trueConfiguration Reference
MongoDBAdapterOptions
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
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
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 MongoDBdisconnect(): 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
- Always call
connect()before using the adapter - Use connection pooling for production (configured automatically)
- Enable
retryWritesfor automatic retry on transient failures - Monitor indexes with MongoDB Atlas or your monitoring tool
- Set appropriate TTL for sessions based on your security needs
- Use strong JWT secrets - minimum 32 bytes of entropy
- Validate all inputs - use provided validation functions
- Handle email sending errors gracefully - async, non-blocking
- Implement rate limiting for authentication endpoints
- Log authentication events for audit trails
Troubleshooting
Connection Issues
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:
await adapter.disconnect()
// Remove old collection in MongoDB
await adapter.connect() // Recreates with fresh indexesPerformance Optimization
For high-traffic applications, tune these settings:
const adapter = new MongoDBStorageAdapter(uri, {
maxPoolSize: 100,
minPoolSize: 25,
maxIdleTimeMS: 60000
})License
MIT
