📜 The Digital Seal: JWT Authentication
JSON Web Tokens (JWT) serve as modern digital seals for API authentication, combining header, payload, and signature into a compact, self-contained token format. This guide explores comprehensive JWT implementation for OpenAI API gateways.
Header
Contains token type and signing algorithm metadata
Payload
Carries claims about the user and additional data
Signature
Digital signature to verify token integrity
⚙️ Signing Algorithm Selection
Choose the appropriate signing algorithm based on your security requirements and infrastructure:
HS256
HMAC with SHA-256
Use: Internal systems
Security: 🔐🔐🔐
RS256
RSA with SHA-256
Use: Public APIs
Security: 🔐🔐🔐🔐
ES256
ECDSA with SHA-256
Use: High-security systems
Security: 🔐🔐🔐🔐🔐
None
No signature (dangerous)
Use: Testing only
Security: 🔐
🛠️ Implementation Guide
1. Token Generation
Generate JWTs with proper claims, expiration, and digital signatures.
// JWT generation example
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
function generateJWT(user) {
const payload = {
sub: user.id,
name: user.name,
email: user.email,
roles: user.roles,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + (60 * 60), // 1 hour
iss: 'api-gateway',
aud: 'openai-api'
};
// Use RSA private key for signing
const privateKey = process.env.JWT_PRIVATE_KEY;
return jwt.sign(payload, privateKey, {
algorithm: 'RS256',
header: {
alg: 'RS256',
typ: 'JWT'
}
});
}
// Generate token
const user = {
id: 'user_123',
name: 'John Doe',
email: 'john@example.com',
roles: ['user', 'api_access']
};
const token = generateJWT(user);
console.log('Generated JWT:', token);
2. Token Validation Middleware
Implement middleware to validate JWTs on incoming API requests.
// JWT validation middleware
const jwksClient = require('jwks-rsa');
// JWKS client for fetching public keys
const client = jwksClient({
jwksUri: 'https://auth-server.com/.well-known/jwks.json',
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 10
});
function getKey(header, callback) {
client.getSigningKey(header.kid, (err, key) => {
if (err) {
return callback(err);
}
const signingKey = key.getPublicKey();
callback(null, signingKey);
});
}
const jwtValidator = (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({
error: 'Authentication required',
code: 'MISSING_TOKEN'
});
}
const token = authHeader.split(' ')[1];
// Verify token signature and claims
jwt.verify(token, getKey, {
algorithms: ['RS256'],
issuer: 'api-gateway',
audience: 'openai-api',
clockTolerance: 30 // 30 seconds tolerance
}, (err, decoded) => {
if (err) {
return res.status(401).json({
error: 'Invalid token',
code: 'INVALID_TOKEN',
details: err.message
});
}
// Check token expiration
const now = Math.floor(Date.now() / 1000);
if (decoded.exp < now) {
return res.status(401).json({
error: 'Token expired',
code: 'TOKEN_EXPIRED'
});
}
// Token is valid, attach to request
req.user = decoded;
req.token = token;
next();
});
};
// Protect API routes
app.use('/api/protected', jwtValidator);
app.get('/api/protected/data', (req, res) => {
res.json({
message: 'Access granted',
user: req.user.sub,
scopes: req.user.roles
});
});
3. Refresh Token Mechanism
Implement secure refresh token mechanism for long-lived sessions.
// Refresh token implementation
const crypto = require('crypto');
class TokenService {
constructor() {
this.refreshTokens = new Map();
}
generateRefreshToken(userId) {
const refreshToken = crypto.randomBytes(64).toString('hex');
const expiresAt = Date.now() + (30 * 24 * 60 * 60 * 1000); // 30 days
// Store refresh token (in production, use database)
this.refreshTokens.set(refreshToken, {
userId,
expiresAt,
createdAt: Date.now()
});
return refreshToken;
}
validateRefreshToken(refreshToken) {
const tokenData = this.refreshTokens.get(refreshToken);
if (!tokenData) {
throw new Error('Invalid refresh token');
}
if (tokenData.expiresAt < Date.now()) {
this.refreshTokens.delete(refreshToken);
throw new Error('Refresh token expired');
}
return tokenData.userId;
}
revokeRefreshToken(refreshToken) {
this.refreshTokens.delete(refreshToken);
}
}
// Token refresh endpoint
app.post('/api/auth/refresh', (req, res) => {
const { refreshToken } = req.body;
if (!refreshToken) {
return res.status(400).json({ error: 'Refresh token required' });
}
try {
const tokenService = new TokenService();
const userId = tokenService.validateRefreshToken(refreshToken);
// Generate new access token
const newAccessToken = generateJWT({ id: userId });
// Optionally rotate refresh token
const newRefreshToken = tokenService.generateRefreshToken(userId);
tokenService.revokeRefreshToken(refreshToken);
res.json({
access_token: newAccessToken,
refresh_token: newRefreshToken,
token_type: 'Bearer',
expires_in: 3600
});
} catch (error) {
res.status(401).json({ error: error.message });
}
});