Authentication is one of those things every web developer has to implement but rarely understands deeply. Most of us just copy a tutorial and hope for the best. Let’s fix that.
Session-Based Authentication
The traditional approach. Here’s how it works:
- User sends username and password
- Server verifies credentials, creates a session object stored in memory or a database
- Server sends back a session ID as a cookie
- Browser automatically sends this cookie with every subsequent request
- Server looks up the session ID to identify the user
# Server-side session creation (Flask example)
from flask import session
@app.route('/login', methods=['POST'])
def login():
user = verify_credentials(request.json)
if user:
session['user_id'] = user.id
session['role'] = user.role
return jsonify({'message': 'Logged in'})
return jsonify({'error': 'Invalid credentials'}), 401
JWT (JSON Web Token) Authentication
The modern approach for APIs:
- User sends username and password
- Server verifies credentials, creates a signed JWT containing user info
- Server sends the JWT to the client
- Client stores it (localStorage or cookie) and sends it in the Authorization header
- Server verifies the JWT signature – no database lookup needed
import jwt
from datetime import datetime, timedelta
SECRET = 'your-secret-key'
def create_token(user):
payload = {
'user_id': user.id,
'role': user.role,
'exp': datetime.utcnow() + timedelta(hours=24)
}
return jwt.encode(payload, SECRET, algorithm='HS256')
def verify_token(token):
try:
return jwt.decode(token, SECRET, algorithms=['HS256'])
except jwt.ExpiredSignatureError:
return None
Honest Comparison
Session Advantages
- Server can revoke sessions instantly (logout works immediately)
- Session data stays on the server (more secure)
- Cookies are sent automatically by the browser
- Simpler mental model
JWT Advantages
- Stateless – server doesn’t need to store anything
- Works across different domains and services
- Great for microservices where multiple services need to verify identity
- Mobile apps and SPAs can store tokens easily
JWT Disadvantages (That Articles Don’t Mention)
- You can’t truly “log out” – the token is valid until it expires
- Storing tokens in localStorage is vulnerable to XSS
- Token size is larger than a session cookie
- Refresh token logic adds significant complexity
My Recommendation
Server-rendered app with one backend? Use sessions. They’re simpler and more secure.
SPA with a separate API backend? Use JWTs in httpOnly cookies (not localStorage).
Microservices? JWTs with short expiration times and refresh tokens.
Security Regardless of Approach
- Always use HTTPS
- Hash passwords with bcrypt or Argon2
- Implement rate limiting on auth endpoints
- Use HttpOnly, Secure, and SameSite cookie attributes
- Add CSRF protection for cookie-based auth
Don’t roll your own crypto. Use established libraries (passport.js, Flask-Login, Spring Security). Authentication is one area where “boring and proven” beats “clever and custom” every time.
