Modern API security relies on two fundamental technologies: OAuth 2.0 for authorization and JSON Web Tokens (JWT) for secure token-based authentication.
OAuth 2.0 is an authorization framework that enables applications to obtain limited access to user accounts. The most common grant types are:
Here's a Node.js example using the express and axios libraries:
const express = require('express');
const axios = require('axios');
const app = express();
const CLIENT_ID = 'your_client_id';
const CLIENT_SECRET = 'your_client_secret';
const REDIRECT_URI = 'http://localhost:3000/callback';
app.get('/login', (req, res) => {
const authUrl = `https://auth-provider.com/oauth2/authorize?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=read`;
res.redirect(authUrl);
});
app.get('/callback', async (req, res) => {
const { code } = req.query;
try {
const response = await axios.post('https://auth-provider.com/oauth2/token', {
grant_type: 'authorization_code',
code,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI
}, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
const { access_token, refresh_token } = response.data;
// Store tokens securely and proceed with API calls
res.send('Authentication successful!');
} catch (error) {
res.status(500).send('Authentication failed');
}
});
app.listen(3000, () => console.log('Server running'));
JWTs provide a stateless way to authenticate API requests. A JWT consists of three parts:
Here's a Python example using PyJWT:
import jwt
import datetime
from jwt.exceptions import InvalidSignatureError, ExpiredSignatureError
SECRET_KEY = 'your-256-bit-secret'
ALGORITHM = 'HS256'
def create_jwt(user_id: str) -> str:
payload = {
'sub': user_id,
'iat': datetime.datetime.utcnow(),
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
}
return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
def validate_jwt(token: str) -> dict:
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except ExpiredSignatureError:
raise Exception('Token expired')
except InvalidSignatureError:
raise Exception('Invalid token')
Modern implementations often use OAuth 2.0 for initial authorization and JWTs for subsequent API authentication. Here's how they work together:
Authorization: Bearer headerconst jwt = require('jsonwebtoken');
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) return res.sendStatus(401);
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
}
// Protected route example
app.get('/protected', authenticateToken, (req, res) => {
res.json({ message: 'Secure data', user: req.user.sub });
});
Token Storage
CSRF Protection
Token Rotation
Scope Limitation
Next steps would be implementing token refresh mechanisms, adding rate limiting, and setting up proper monitoring for authentication attempts. Always conduct security audits before deploying authentication systems to production.