Back to Blog
API security
API management
GraphQL
API versioning

API Security: OAuth 2.0 and JWT Implementation

3 min read
J
John
Senior API Architect

API Security: OAuth 2.0 and JWT Implementation

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 Fundamentals

OAuth 2.0 is an authorization framework that enables applications to obtain limited access to user accounts. The most common grant types are:

  • Authorization Code (for server-side apps)
  • Client Credentials (for machine-to-machine auth)
  • Refresh Token (for long-lived sessions)

Authorization Code Flow Implementation

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'));

JWT Implementation

JWTs provide a stateless way to authenticate API requests. A JWT consists of three parts:

  1. Header (algorithm and token type)
  2. Payload (claims about the user)
  3. Signature (verifies the token)

Generating and Validating JWTs

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')

Secure JWT Best Practices

  1. Always verify the signature
  2. Set reasonable expiration times (15-30 minutes for access tokens)
  3. Use HTTPS exclusively
  4. Store secrets securely (never in code)
  5. Implement token revocation for sensitive operations

Combining OAuth 2.0 and JWT

Modern implementations often use OAuth 2.0 for initial authorization and JWTs for subsequent API authentication. Here's how they work together:

  1. Client obtains an OAuth access token
  2. Authorization server issues a JWT
  3. Client includes JWT in Authorization: Bearer header
  4. Resource server validates the JWT

Express Middleware for JWT Validation

const 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 });
});

Security Considerations

  1. Token Storage

    • Web: Use HTTP-only, Secure, SameSite cookies
    • Mobile: Use secure storage (Keychain/Keystore)
  2. CSRF Protection

    • Implement state parameter in OAuth flows
    • Use anti-CSRF tokens for web apps
  3. Token Rotation

    • Rotate refresh tokens after each use
    • Implement short-lived access tokens
  4. Scope Limitation

    • Follow principle of least privilege
    • Validate scopes for each API request

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.

Back to Blog