Authentication is fundamental to application security, yet it's easy to get wrong. Understanding the patterns, their trade-offs, and security implications helps you choose the right approach for your application.
Authentication vs Authorization#
Authentication: Verifying identity ("Who are you?") Authorization: Checking permissions ("What can you do?")
Session-Based Authentication#
How It Works#
1. User logs in with credentials
2. Server creates session, stores in database/Redis
3. Server sends session ID in cookie
4. Browser sends cookie with each request
5. Server validates session ID, retrieves user
Implementation#
Pros and Cons#
Pros:
✓ Easy to invalidate (delete from store)
✓ Session data stays on server
✓ Works well with traditional web apps
✓ Simple to understand
Cons:
✗ Requires server-side storage
✗ Harder to scale (need shared session store)
✗ Not ideal for APIs consumed by mobile/SPAs
JWT (JSON Web Tokens)#
How It Works#
1. User logs in with credentials
2. Server creates signed JWT with user claims
3. Server sends JWT to client
4. Client stores JWT and sends in Authorization header
5. Server validates signature and extracts claims
Structure#
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. // Header
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4ifQ. // Payload
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c // Signature
Implementation#
Token Refresh#
Pros and Cons#
Pros:
✓ Stateless (no server-side storage for access tokens)
✓ Works well for APIs and microservices
✓ Self-contained (includes user data)
✓ Easy to scale
Cons:
✗ Can't invalidate before expiry (without blocklist)
✗ Larger payload than session IDs
✗ Must handle token refresh
✗ Security-sensitive to implement correctly
OAuth 2.0 / OpenID Connect#
Common Flows#
Authorization Code Flow (recommended for web apps):
1. Redirect user to provider
2. User authenticates with provider
3. Provider redirects back with code
4. Exchange code for tokens
5. Use tokens to access resources
PKCE (for SPAs and mobile):
Same as above, but with code_verifier/code_challenge
to prevent code interception attacks
Implementation with NextAuth.js#
Security Best Practices#
Password Handling#
Token Storage (Client-Side)#
Access Tokens:
✓ In-memory (JavaScript variable)
✓ Short-lived (15 minutes)
✗ Not in localStorage (XSS vulnerable)
Refresh Tokens:
✓ httpOnly cookie (prevents XSS)
✓ Secure flag (HTTPS only)
✓ SameSite attribute
✗ Not in localStorage
CSRF Protection#
Rate Limiting#
Multi-Factor Authentication#
Choosing the Right Pattern#
Traditional Web App:
→ Sessions with cookies
API for Mobile/SPA:
→ JWT with refresh tokens
Third-Party Login:
→ OAuth 2.0 / OpenID Connect
High Security:
→ Sessions + MFA
→ Short-lived tokens + refresh rotation
Conclusion#
Authentication is security-critical and complex. Use established libraries and patterns rather than rolling your own. Understand the trade-offs between stateful (sessions) and stateless (JWT) approaches, and choose based on your application's needs.
Security isn't a feature—it's a requirement. Implement defense in depth with rate limiting, proper password hashing, secure token storage, and multi-factor authentication.