API Authentication Headers
API Authentication Headers
JWT-Based API Authentication
class APIAuthenticationHeaders {
constructor() {
this.jwtSecret = process.env.JWT_SECRET;
this.jwtExpiry = '1h';
this.refreshExpiry = '7d';
}
// Generate tokens with security headers
generateTokens(user, res) {
const accessToken = jwt.sign(
{
userId: user.id,
type: 'access',
fingerprint: this.generateTokenFingerprint()
},
this.jwtSecret,
{
expiresIn: this.jwtExpiry,
issuer: 'api.example.com',
audience: 'app.example.com'
}
);
const refreshToken = jwt.sign(
{
userId: user.id,
type: 'refresh',
tokenFamily: uuid.v4()
},
this.jwtSecret,
{
expiresIn: this.refreshExpiry,
issuer: 'api.example.com'
}
);
// Set tokens in secure cookies
res.cookie('access_token', accessToken, {
secure: true,
httpOnly: true,
sameSite: 'strict',
maxAge: 3600000 // 1 hour
});
res.cookie('refresh_token', refreshToken, {
secure: true,
httpOnly: true,
sameSite: 'strict',
maxAge: 604800000, // 7 days
path: '/api/auth/refresh' // Limit refresh token usage
});
// Also return in response for mobile apps
return { accessToken, refreshToken };
}
// API authentication middleware
authenticateAPI() {
return async (req, res, next) => {
// Check Authorization header
const authHeader = req.headers.authorization;
const cookieToken = req.cookies.access_token;
const token = authHeader?.split(' ')[1] || cookieToken;
if (!token) {
res.setHeader('WWW-Authenticate', 'Bearer realm="API"');
return res.status(401).json({ error: 'Authentication required' });
}
try {
const decoded = jwt.verify(token, this.jwtSecret, {
issuer: 'api.example.com',
audience: 'app.example.com'
});
// Additional validation
if (decoded.type !== 'access') {
throw new Error('Invalid token type');
}
req.user = { id: decoded.userId };
// Set security headers for authenticated requests
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Cache-Control', 'private, no-cache');
next();
} catch (error) {
res.setHeader('WWW-Authenticate',
`Bearer realm="API", error="invalid_token", error_description="${error.message}"`
);
return res.status(401).json({ error: 'Invalid token' });
}
};
}
}