User registration is the first interaction many users have with your API. In this lesson, we'll implement secure user signup with password hashing, understand why we hash passwords, and explore email verification strategies used in production applications.
<aside> 🎯
Registration Flow:
Storing passwords in plain text is one of the worst security mistakes you can make. Here's why hashing is critical:
-- Database breach exposes:
id | email | password
1 | [[email protected]](<mailto:[email protected]>) | MyPassword123!
2 | [[email protected]](<mailto:[email protected]>) | admin2024
Consequences:
-- Database breach exposes:
id | email | password
1 | [[email protected]](<mailto:[email protected]>) | $2b$12$N9qo8uL...
2 | [[email protected]](<mailto:[email protected]>) | $2b$12$K7xI9pQ...
Protection:
<aside> ⚠️
Real World Breaches:
Don't be the next headline - always hash passwords!
</aside>
Bcrypt is specifically designed for password hashing with built-in protection:
// Input password
"MyPassword123!"
// Bcrypt process:
1. Generate random salt: "$2b$12$N9qo8uLOickgx2ZMRZoMye"
2. Combine password + salt
3. Apply blowfish algorithm 2^12 times (4,096 iterations)
4. Output hash: "$2b$12$N9qo8uLOickgx2ZMRZoMye.IjQ0JwF2cJX8nnYA5VYA.KQIeqHLWa"
<aside> 📝
File: src/controllers/authController.ts
</aside>
import type { Request, Response } from 'express'
import bcrypt from 'bcrypt'
import { generateToken } from '../utils/jwt.ts'
import { db } from '../db/connection.ts'
import { users } from '../db/schema.ts'
export const register = async (req: Request, res: Response) => {
try {
const { email, username, password, firstName, lastName } = req.body
// Hash password with configurable rounds
const saltRounds = parseInt(process.env.BCRYPT_SALT_ROUNDS || '12')
const hashedPassword = await bcrypt.hash(password, saltRounds)
// Create user in database
const [newUser] = await db
.insert(users)
.values({
email,
username,
password: hashedPassword, // Store hash, not plain text!
firstName,
lastName,
})
.returning({
id: [users.id](<http://users.id>),
email: [users.email](<http://users.email>),
username: users.username,
firstName: users.firstName,
lastName: users.lastName,
createdAt: users.createdAt,
})
// Generate JWT for auto-login
const token = await generateToken({
id: [newUser.id](<http://newUser.id>),
email: [newUser.email](<http://newUser.email>),
username: newUser.username,
})
res.status(201).json({
message: 'User created successfully',
user: newUser,
token, // User is logged in immediately
})
} catch (error) {
console.error('Registration error:', error)
res.status(500).json({ error: 'Failed to create user' })
}
}