localgreenchain/pages/api/auth/register.ts
Claude 39b6081baa
Implement comprehensive authentication system (Agent 1)
Add complete user authentication with NextAuth.js supporting:
- Email/password credentials authentication
- OAuth providers (GitHub, Google) with optional configuration
- JWT-based session management with 30-day expiry
- Role-based access control (USER, GROWER, FARM_MANAGER, ADMIN)
- Permission system with granular access control
- Secure password hashing with bcrypt (12 rounds)
- Rate limiting on auth endpoints
- Password reset flow with secure tokens
- Email verification system

Files added:
- lib/auth/: Core auth library (types, permissions, context, hooks, middleware)
- pages/api/auth/: Auth API routes (NextAuth, register, forgot-password, verify-email)
- pages/auth/: Auth pages (signin, signup, forgot-password, reset-password, verify-email)
- components/auth/: Reusable auth components (LoginForm, RegisterForm, AuthGuard, etc.)

Updated _app.tsx to include SessionProvider for auth state management.
2025-11-23 03:52:09 +00:00

119 lines
3.3 KiB
TypeScript

import type { NextApiRequest, NextApiResponse } from 'next'
import bcrypt from 'bcryptjs'
import { createUser, findUserByEmail } from './[...nextauth]'
import { UserRole, AuthResponse, RegisterInput } from '@/lib/auth/types'
import { withRateLimit } from '@/lib/auth/withAuth'
const BCRYPT_ROUNDS = 12 // Secure password hashing
async function handler(
req: NextApiRequest,
res: NextApiResponse<AuthResponse>
) {
if (req.method !== 'POST') {
return res.status(405).json({
success: false,
message: 'Method not allowed',
error: 'Only POST requests are accepted',
})
}
try {
const { email, password, name, role }: RegisterInput = req.body
// Validation
if (!email || !password) {
return res.status(400).json({
success: false,
message: 'Email and password are required',
error: 'VALIDATION_ERROR',
})
}
// Email format validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!emailRegex.test(email)) {
return res.status(400).json({
success: false,
message: 'Invalid email format',
error: 'INVALID_EMAIL',
})
}
// Password strength validation
if (password.length < 8) {
return res.status(400).json({
success: false,
message: 'Password must be at least 8 characters long',
error: 'WEAK_PASSWORD',
})
}
// Check password complexity
const hasUpperCase = /[A-Z]/.test(password)
const hasLowerCase = /[a-z]/.test(password)
const hasNumbers = /\d/.test(password)
if (!hasUpperCase || !hasLowerCase || !hasNumbers) {
return res.status(400).json({
success: false,
message: 'Password must contain uppercase, lowercase, and numbers',
error: 'WEAK_PASSWORD',
})
}
// Check if user already exists
const existingUser = findUserByEmail(email)
if (existingUser) {
return res.status(409).json({
success: false,
message: 'An account with this email already exists',
error: 'USER_EXISTS',
})
}
// Hash password with bcrypt
const passwordHash = await bcrypt.hash(password, BCRYPT_ROUNDS)
// Determine role (default to USER, only admin can assign higher roles)
// In a real app, you'd check if the requester has admin permissions
const userRole = role === UserRole.ADMIN ? UserRole.USER : (role || UserRole.USER)
// Create user
const user = createUser({
email: email.toLowerCase(),
name: name || undefined,
passwordHash,
role: userRole,
})
// TODO: Send verification email (will be implemented with Agent 8 - Notifications)
console.log(`New user registered: ${user.email}`)
return res.status(201).json({
success: true,
message: 'Registration successful. Please sign in.',
user: {
id: user.id,
email: user.email,
name: user.name,
role: user.role,
image: user.image,
emailVerified: user.emailVerified,
},
})
} catch (error) {
console.error('Registration error:', error)
return res.status(500).json({
success: false,
message: 'An error occurred during registration',
error: 'INTERNAL_ERROR',
})
}
}
// Apply rate limiting: 5 registrations per minute per IP
export default withRateLimit(handler, {
limit: 5,
windowMs: 60000,
})