Security
Authentication
Backend
OAuth
JWT
Ask anything about this article
Hi! I've read this article.
What would you like to know?
@farhan
Authentication is the most critical part of any application. Get it wrong, and everything else doesn't matter. Here's how to get it right.
1. User clicks "Login with Google"
2. → Redirect to Google's auth page
3. ← User grants permission
4. → Google redirects back with authorization CODE
5. → Your server exchanges code for tokens (server-to-server)
6. ← Receives access_token + refresh_token
typescript// Step 1: Generate code verifier + challenge
const codeVerifier = generateRandomString(128);
const codeChallenge = base64url(sha256(codeVerifier));
// Step 2: Redirect to auth server
const authUrl = new URL('https://auth.example.com/authorize');
authUrl.searchParams.set('client_id', CLIENT_ID);
authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('code_challenge', codeChallenge);
authUrl.searchParams.set('code_challenge_method', 'S256');
// Step 3: Exchange code + verifier for tokens
const tokens = await fetch('https://auth.example.com/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authCode,
code_verifier: codeVerifier, // Proves we're the original requester
client_id: CLIENT_ID,
})
});
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NSIsIm5hbWUiOiJGYXJoYW4ifQ.signature
│ │ │
Header Payload Signature
(algorithm) (claims/data) (verification)
typescriptimport jwt from 'jsonwebtoken';
// Creating a token
const token = jwt.sign(
{
sub: user.id,
email: user.email,
role: user.role
},
process.env.JWT_SECRET!,
{
expiresIn: '15m', // Short-lived!
issuer: 'myapp.com'
}
);
// Verifying a token
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET!);
// Token is valid, decoded contains the payload
} catch (err) {
if (err.name === 'TokenExpiredError') {
// Token expired — use refresh token
} else {
// Invalid token — reject request
}
}
Access Token: Short-lived (15 min), sent with every request
Refresh Token: Long-lived (7 days), used to get new access tokens
Flow:
1. Access token expires
2. Client sends refresh token to /auth/refresh
3. Server validates refresh token
4. Server issues NEW access + refresh tokens
5. OLD refresh token is invalidated (rotation)
| Pitfall | Risk | Solution |
|---|---|---|
| Storing JWT in localStorage | XSS can steal tokens | Use httpOnly cookies |
| No token expiration | Stolen token works forever | 15 min access, 7 day refresh |
| Weak JWT secret | Tokens can be forged | Use 256+ bit random secret |
| No token rotation | Leaked refresh token reusable | Rotate on every refresh |
| Missing CSRF protection | Cross-site request forgery | SameSite cookies + CSRF token |
Get authentication right from day one. Retrofitting security is always harder than building it in.