Authentication Best Practices

Easyβ€’

Authentication is fundamental to web security. Following best practices prevents common vulnerabilities and ensures user data protection.

Quick Decision Guide

Quick Implementation Guide:

Password Hashing: Use bcrypt: const hash = await bcrypt.hash(password, 10). Never store plain passwords.

JWT Tokens: Use for stateless auth: jwt.sign({ userId }, SECRET, { expiresIn: '24h' }). Store in httpOnly cookie or localStorage (less secure).

Sessions: Use secure, httpOnly cookies: cookie: { secure: true, httpOnly: true, sameSite: 'strict' }

Rate Limiting: Prevent brute force: rateLimit({ windowMs: 15<em>60</em>1000, max: 5 }) on login endpoints.

Password Requirements: Minimum 8 chars, require complexity, check against common passwords list.

Security Checklist: - βœ… Hash passwords with salt (bcrypt/Argon2) - βœ… Use HTTPS only - βœ… HttpOnly cookies for sessions - βœ… Rate limit login attempts - βœ… Regenerate session ID after login - βœ… Set token expiration (24h max for JWTs)

Never: Store plain passwords, trust client validation, or put tokens in URLs.

Understanding Authentication Flow

Overview of Authentication

Authentication verifies who a user is. It's the process of confirming a user's identity before granting access to protected resources.

Figure 1: Authentication Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   User      β”‚         β”‚   Server     β”‚         β”‚   Database   β”‚
β”‚  Browser    β”‚         β”‚              β”‚         β”‚              β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
       β”‚                       β”‚                        β”‚
       β”‚ 1. Submit Credentials β”‚                        β”‚
       β”‚    (username/password)β”‚                        β”‚
       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€>                        β”‚
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ 2. Query User         β”‚
       β”‚                       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€>
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ <───────────────────────
       β”‚                       β”‚    User Record        β”‚
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ 3. Verify Password    β”‚
       β”‚                       β”‚    (compare hash)     β”‚
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ 4. Generate Token/    β”‚
       β”‚                       β”‚    Session            β”‚
       β”‚                       β”‚                        β”‚
       β”‚ <───────────────────────                        β”‚
       β”‚    Token/Session      β”‚                        β”‚
       β”‚                       β”‚                        β”‚
       β”‚ 5. Store Token        β”‚                        β”‚
       β”‚    (cookie/localStorage)β”‚                        β”‚
       β”‚                       β”‚                        β”‚

Authentication Methods

1. Password-Based Authentication

β€’Most common method
β€’Username + password combination
β€’Requires secure password storage

2. Token-Based Authentication (JWT)

β€’Stateless authentication
β€’Token contains user claims
β€’No server-side session storage needed

3. OAuth 2.0

β€’Third-party authentication
β€’Delegated authorization
β€’Used by Google, GitHub, etc.

4. Multi-Factor Authentication (MFA)

β€’Multiple verification factors
β€’Something you know (password)
β€’Something you have (phone, hardware token)
β€’Something you are (biometric)

Password Security

Never Store Plain Text Passwords

Figure 2: Password Storage Comparison

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Password Storage Methods                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                          β”‚
β”‚  ❌ Plain Text (DANGEROUS)                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚
β”‚  β”‚ Password: "mypassword123"            β”‚             β”‚
β”‚  β”‚ Stored: "mypassword123"              β”‚             β”‚
β”‚  β”‚                                       β”‚             β”‚
β”‚  β”‚ Risk: Immediate access if DB leaked   β”‚             β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚
β”‚                                                          β”‚
β”‚  ❌ Basic Hashing (VULNERABLE)                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚
β”‚  β”‚ Password: "mypassword123"            β”‚             β”‚
β”‚  β”‚ Hash: SHA256("mypassword123")        β”‚             β”‚
β”‚  β”‚                                       β”‚             β”‚
β”‚  β”‚ Risk: Rainbow table attacks          β”‚             β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚
β”‚                                                          β”‚
β”‚  βœ… Salted Hashing (SECURE)                            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚
β”‚  β”‚ Password: "mypassword123"            β”‚             β”‚
β”‚  β”‚ Salt: "random_salt_abc123"          β”‚             β”‚
β”‚  β”‚ Hash: bcrypt(password + salt)        β”‚             β”‚
β”‚  β”‚                                       β”‚             β”‚
β”‚  β”‚ Safe: Unique hash per password       β”‚             β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚
β”‚                                                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Password Hashing Process

Figure 3: Password Hashing Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   User      β”‚         β”‚   Server     β”‚         β”‚   Database   β”‚
β”‚ Registrationβ”‚         β”‚              β”‚         β”‚              β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
       β”‚                       β”‚                        β”‚
       β”‚ 1. Submit Password    β”‚                        β”‚
       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€>                        β”‚
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ 2. Generate Salt      β”‚
       β”‚                       β”‚    (random)            β”‚
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ 3. Hash Password      β”‚
       β”‚                       β”‚    bcrypt(password + salt)β”‚
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ 4. Store Hash + Salt  β”‚
       β”‚                       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€>
       β”‚                       β”‚                        β”‚
       β”‚ <───────────────────────                        β”‚
       β”‚    Success            β”‚                        β”‚
       β”‚                       β”‚                        β”‚

Use Hashing Algorithm:

β€’bcrypt (recommended) - Adaptive hashing, slow by design
β€’Argon2 (modern, more secure) - Winner of Password Hashing Competition
β€’scrypt (good alternative) - Memory-hard function

Salt Passwords:

β€’Add random salt to each password
β€’Prevents rainbow table attacks
β€’Each password hash is unique (even same password = different hash)

Password Requirements

β€’Minimum length: 8-12 characters
β€’Require complexity: uppercase, lowercase, numbers, symbols
β€’Check against common passwords: Use password strength checker
β€’Implement rate limiting: Prevent brute force attacks on login attempts

Session Management

Session vs Token-Based Authentication

Figure 4: Session-Based Authentication Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   User      β”‚         β”‚   Server     β”‚         β”‚   Session   β”‚
β”‚  Browser    β”‚         β”‚              β”‚         β”‚   Store     β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
       β”‚                       β”‚                        β”‚
       β”‚ 1. Login              β”‚                        β”‚
       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€>                        β”‚
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ 2. Create Session     β”‚
       β”‚                       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€>
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ <───────────────────────
       β”‚                       β”‚    Session ID          β”‚
       β”‚                       β”‚                        β”‚
       β”‚ <───────────────────────                        β”‚
       β”‚    Session Cookie     β”‚                        β”‚
       β”‚    (sessionId)       β”‚                        β”‚
       β”‚                       β”‚                        β”‚
       β”‚ 3. Request with Cookieβ”‚                        β”‚
       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€>                        β”‚
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ 4. Validate Session   β”‚
       β”‚                       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€>
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ <───────────────────────
       β”‚                       β”‚    Session Data        β”‚
       β”‚                       β”‚                        β”‚
       β”‚ <───────────────────────                        β”‚
       β”‚    Authorized         β”‚                        β”‚
       β”‚                       β”‚                        β”‚

Figure 5: Token-Based Authentication Flow (JWT)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   User      β”‚         β”‚   Server     β”‚
β”‚  Browser    β”‚         β”‚              β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚                       β”‚
       β”‚ 1. Login              β”‚
       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€>
       β”‚                       β”‚
       β”‚                       β”‚ 2. Generate JWT       β”‚
       β”‚                       β”‚    (signed token)     β”‚
       β”‚                       β”‚                        β”‚
       β”‚ <───────────────────────                        β”‚
       β”‚    JWT Token          β”‚                        β”‚
       β”‚    (contains user info)β”‚                        β”‚
       β”‚                       β”‚                        β”‚
       β”‚ 3. Store Token        β”‚                        β”‚
       β”‚    (localStorage/cookie)β”‚                        β”‚
       β”‚                       β”‚                        β”‚
       β”‚ 4. Request with Token β”‚                        β”‚
       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€>                        β”‚
       β”‚                       β”‚                        β”‚
       β”‚                       β”‚ 5. Verify Token       β”‚
       β”‚                       β”‚    (check signature)  β”‚
       β”‚                       β”‚                        β”‚
       β”‚ <───────────────────────                        β”‚
       β”‚    Authorized         β”‚                        β”‚
       β”‚                       β”‚                        β”‚
AspectServer-Side SessionsToken-Based (JWT)
StorageServer-sideClient-side
ScalabilityRequires shared storageStateless
RevocationEasy (delete session)Hard (wait for expiry)
SecurityMore secureLess secure (if stolen)
Use CaseTraditional appsMicroservices, APIs
res.cookie('session', sessionId, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'strict',
  maxAge: 24 * 60 * 60 * 1000 // 24 hours
});

Authentication Methods Comparison

MethodSecurityComplexityUse Case
Password-Based⭐⭐⭐ MediumLowMost common, simple apps
JWT Tokens⭐⭐⭐⭐ HighMediumAPIs, microservices
OAuth 2.0⭐⭐⭐⭐⭐ HighestHighThird-party login
MFA⭐⭐⭐⭐⭐ HighestHighSensitive accounts

Best Practices for Implementation

Security Checklist

Password Security:

β€’βœ… Hash passwords with salt (bcrypt/Argon2)
β€’βœ… Never store plain text passwords
β€’βœ… Enforce password complexity requirements
β€’βœ… Check against common passwords list
β€’βœ… Implement password reset securely

Rate Limiting:

β€’βœ… Limit login attempts (e.g., 5 attempts per 15 minutes)
β€’βœ… Implement account lockout after failed attempts
β€’βœ… Use CAPTCHA after multiple failures

Session Management:

β€’βœ… Use httpOnly cookies for sessions
β€’βœ… Set secure flag (HTTPS only)
β€’βœ… Implement session expiration
β€’βœ… Regenerate session ID after login
β€’βœ… Implement session invalidation on logout

Token Security:

β€’βœ… Set token expiration (24h max for JWTs)
β€’βœ… Use refresh tokens for long-lived sessions
β€’βœ… Store tokens securely (httpOnly cookies preferred)
β€’βœ… Never put tokens in URLs
β€’βœ… Implement token revocation

General Security:

β€’βœ… Use HTTPS only
β€’βœ… Validate all input server-side
β€’βœ… Never trust client-side validation
β€’βœ… Implement CSRF protection
β€’βœ… Log authentication events

Common Mistakes to Avoid

Mistake 1: Storing plain text passwords

β€’βŒ password: "mypassword123"
β€’βœ… passwordHash: bcrypt.hash("mypassword123", salt)

Mistake 2: Not rate limiting login

β€’βŒ Unlimited login attempts
β€’βœ… Rate limit: 5 attempts per 15 minutes

Mistake 3: Weak session management

β€’βŒ Session cookies without httpOnly flag
β€’βœ… httpOnly: true, secure: true, sameSite: 'strict'

Mistake 4: Long-lived tokens

β€’βŒ JWT with no expiration
β€’βœ… JWT with 24h expiration + refresh token

Mistake 5: Trusting client validation

β€’βŒ Only client-side password validation
β€’βœ… Always validate server-side

Key Takeaways

1Never store passwords in plain text - always hash
2Use bcrypt or Argon2 for password hashing
3Implement rate limiting to prevent brute force
4Use httpOnly and secure cookies for sessions
5Implement token expiration and refresh mechanisms
6Consider multi-factor authentication for sensitive accounts