Authentication verifies who a user is. In this lesson, you will build a complete authentication system with registration, login, password hashing, JSON Web Tokens (JWT), and protected routes.
Authentication Flow
A typical token-based authentication flow:
- User registers with email and password
- Server hashes the password and stores the user
- User logs in with credentials
- Server verifies credentials and returns a JWT
- Client sends the JWT with every subsequent request
- Server verifies the JWT and grants access
Setting Up
Install the required packages:
npm install bcrypt jsonwebtokenbcrypt— hashes passwords securelyjsonwebtoken— creates and verifies JWTs
Password Hashing
Never store plain-text passwords. Use bcrypt to hash them:
Higher salt rounds mean slower hashing (more secure but slower). 12 is a good default.
JSON Web Tokens
A JWT contains a header, payload, and signature. The server signs the token with a secret key, and can later verify it without a database lookup.
JWT Structure
A JWT looks like xxxxx.yyyyy.zzzzz — three base64-encoded parts separated by dots:
| Part | Contains |
|---|---|
| Header | Algorithm and token type |
| Payload | User data (claims) and expiration |
| Signature | Verification hash (header + payload + secret) |
User Registration
User Login
Notice we return the same error message for both "user not found" and "wrong password." This prevents attackers from discovering which emails are registered.
Auth Middleware
Protect routes by verifying the JWT on every request:
Protecting Routes
Security Best Practices
Rate Limit Login Attempts
Security Checklist
| Practice | Why |
|---|---|
| Hash passwords with bcrypt | Protects against database leaks |
| Use HTTPS in production | Prevents token interception |
| Set short JWT expiration | Limits damage from stolen tokens |
| Use httpOnly cookies (optional) | Prevents XSS from accessing tokens |
| Rate limit login attempts | Prevents brute-force attacks |
| Return generic error messages | Prevents user enumeration |
| Validate input length | Prevents DoS via long passwords |
Practical Exercise
Wire everything together into a complete auth system:
Key Takeaways
- Never store plain-text passwords — always hash with bcrypt.
- JWTs let you verify identity without a database lookup on every request.
- Use middleware to protect routes and separate auth logic from business logic.
- Return the same error for "user not found" and "wrong password" to prevent user enumeration.
- Rate limit login attempts and use HTTPS in production.