Introduction
When building an API, front ends need to authenticate users using one of three options: Basic Auth, Bearer Tokens, or JWTs. Pick the wrong one and you'll either overengineer a simple app or create a security nightmare in production.
Basic Auth
The simplest approach
Bearer Tokens
Most common transport
JWTs
Self-contained tokens
💡 Key Concepts
- Why Base64 encoding ≠ encryption
- Bearer scheme vs token types
- How JWT signatures prevent tampering
- localStorage vs httpOnly cookies
- When JWTs are essential
- HS256 vs RS256 algorithms
- Why HTTPS is non-negotiable
- Token revocation strategies
🎯 Who This Is For
- Backend developers building REST APIs
- Frontend devs implementing auth
- Full-stack engineers
- DevOps engineers securing production
- Anyone tired of copy-pasting auth code
The Problem: HTTP is Stateless
HTTP works the same way by design. It keeps things simple and fast, but you must prove who you are with every request.
Authentication asks "Who are you?" (not authorization: "What can you do?").
Basic Authentication
RFC 7617Basic authentication is the simplest HTTP authentication scheme:
- Take username and password
- Join them with a colon
- Encode in Base64
- Send in authorization header with every request
⚠️ Base64 is NOT Encryption
Why Base64? HTTP headers only accept certain characters. Base64 converts username:password into safe characters—it's for compatibility, not security. Anyone can decode it instantly.
Over plain HTTP, you're broadcasting passwords in unencrypted form.
Basic Auth over HTTPS is fine—TLS encryption protects credentials. Over HTTP, it's completely exposed.
The Issue
Credentials are sent with every request—many opportunities for interception or logging. If credentials appear in server logs, cache layers, or proxy logs, that's a security incident waiting to happen.
When to Use Basic Auth
Best for: Internal tools, local development, simple machine-to-machine communication where the network is controlled.
Bearer Token Scheme
Common Misconception
Bearer is the delivery method. The token is the content.
How Bearer Tokens Work (Opaque Tokens)
Getting a Token
Client sends credentials once → Server validates → Generates random token → Stores in database → Sends back to client
Using the Token
Client includes token in authorization header → Server checks database → Grants or denies access
What is an Opaque Token?
Called opaque because the token contains no information—just a random identifier. The server must query the database every time to verify who owns it and if it's valid.
✓ Advantages
- Passwords not sent repeatedly
- Revoke tokens without changing passwords
- Set expiration times
⚠ Trade-offs
- Database lookup every request
- Performance consideration for high-traffic
- Multiple servers need shared storage
The Question: What if the token itself could identify the user without hitting the database?
JWT Deep Dive
JSON Web Tokens (JWTs) are self-contained tokens with data inside them.
JWT Structure: Three Parts
1. Header
Algorithm used to sign the token (e.g., HMAC SHA-256) and token type (JWT).
Determines signature verification method.
2. Payload
Claims: User information
- sub — Subject (user ID)
- exp — Expiration
- iat — Issued at
- Custom claims
3. Signature
Cryptographic hash of header + payload using a secret key.
Makes JWT secure.
🚨 Payload is NOT Encrypted
The payload is only Base64 encoded. Anyone can decode and read it—visit jwt.io and see for yourself.
Never put in a JWT: Passwords, social security numbers, credit card numbers, or any sensitive data.
Only include: Data you're okay with the client seeing (user ID, roles, etc.).
How Signatures Make JWTs Secure
If anyone changes even one character in the payload, the signature won't match and the server will reject it. JWTs are tamper-proof—claims can't be changed without invalidating the signature.
Remember: Tamper-proof ≠ private. The signature prevents changes, but anyone can read the payload.
The Game-Changing Advantage
No database lookup required. The server verifies the signature mathematically—5-10x faster than database queries.
Servers scale horizontally without shared session storage—each server verifies JWTs independently.
The Trade-off: Revocation
JWTs are stateless—the server doesn't track them. Revocation solutions:
- Token blacklist (defeats stateless advantage)
- Short-lived access tokens with refresh token rotation
- Token versioning with user state checks
JWT expiration times are critical—they limit exposure windows.
The Refresh Token Pattern
Best practice: Short-lived access tokens (15 minutes) + longer-lived refresh tokens.
When access tokens expire, clients use refresh tokens to get new ones. Refresh tokens are stored in the database and can be revoked—combining JWT performance with revocation control.
Signing Algorithms
HS256 (Symmetric)
Fast, simple, secure when you control everything.
Use for: Simpler setups with centralized control
RS256 (Asymmetric)
Use for: Microservices where multiple services verify tokens from central auth
Security Best Practices
⚠️ Common Mistakes
- Sending Basic Auth over HTTP (password in plain text)
- Storing sensitive data in JWT payloads (anyone can read it)
- Using localStorage for tokens (XSS vulnerability)
- Creating JWTs that never expire (security nightmare)
- Confusing Bearer scheme with Bearer tokens
- Rolling your own crypto
1. Always Use HTTPS
No authentication method is secure over plain HTTP. HTTPS encrypts the entire request, including headers. No exceptions.
2. Token Storage Matters
localStorage
Vulnerable to XSS (cross-site scripting). Malicious JavaScript can read localStorage and steal tokens.
httpOnly Cookies
Can't be accessed by JavaScript—protects against XSS. But vulnerable to CSRF (cross-site request forgery).
✓ The Solution
Use httpOnly cookies with SameSite attribute set to strict or lax.
3. Set Appropriate Expiration Times
Short-lived access tokens, longer refresh tokens. Don't create year-long JWTs—that's a year-long security window if stolen.
4. Never Roll Your Own Crypto
Use established libraries: jsonwebtoken (Node.js), PyJWT (Python), or similar. These are tested and audited—custom implementations aren't.
5. JWT Algorithm Verification
Classic vulnerability: Attackers change algorithm from RS256 to "none" or HS256 to bypass signature verification.
While modern JWT libraries protect against this by default, explicitly specify the expected algorithm as defense-in-depth. Always whitelist accepted algorithms.
Decision Framework
Internal Tools
Use Basic Auth with HTTPS
Simple, effective, no overengineering.
Public-Facing APIs
Skip Basic Auth
Horizontal Scaling (Multiple Servers)
Use JWTs
Stateless, fast, no shared session storage needed.
Simpler Applications
Use opaque bearer tokens with server-side sessions
Easier to implement and revoke. Database lookups often aren't a performance problem.
Match auth system complexity to actual requirements. Don't use JWTs just because they're trendy.
Recap
Basic Auth
Simple but requires HTTPS and sends credentials repeatedly.
Bearer Scheme
Transport mechanism—tokens can be opaque or JWTs.
Opaque Tokens
Require database lookups but easy to revoke.
JWTs
Self-contained, fast, stateless—perfect for scaling. Harder to revoke without extra infrastructure.