Broken Authentication with Bearer Tokens
How Broken Authentication Manifests in Bearer Tokens
Bearer tokens are widely used for API authentication, but their stateless nature creates specific vulnerabilities when implemented incorrectly. The fundamental issue with bearer tokens is that anyone who possesses the token can use it—there's no additional proof of identity beyond the token itself.
The most common manifestation is missing or weak token validation. Many APIs accept any bearer token format without verifying its structure, expiration, or signature. This allows attackers to use expired tokens, tokens intended for different services, or even completely invalid tokens to access protected resources.
Another critical issue is token exposure through URLs. When bearer tokens are passed as query parameters instead of in the Authorization header, they become visible in browser history, server logs, and referer headers. This simple mistake can expose tokens to anyone with access to these logs.
Session fixation attacks specifically target bearer token implementations. An attacker can force a user to authenticate with a known token value, then use that token to access the user's session. This is particularly dangerous in APIs that don't implement token rotation or proper session invalidation.
Cross-site request forgery (CSRF) becomes more problematic with bearer tokens when they're stored in cookies rather than HTTP-only headers. While bearer tokens in Authorization headers are generally safe from CSRF, token-based authentication in cookies can be exploited if the API doesn't implement proper CSRF protection.
Token replay attacks exploit the fact that bearer tokens are often valid until expiration. If an attacker intercepts a token during transmission (via MITM attacks or through compromised client devices), they can use it repeatedly until it expires. Without additional controls like IP binding or device fingerprinting, the API cannot distinguish between legitimate and malicious token usage.
Improper scope validation is another common issue. APIs often issue tokens with broad permissions, but fail to validate that the token actually has permission to access specific resources. An attacker with a token that has read access might be able to perform write operations if the API doesn't properly check token scopes against requested operations.
Here's a vulnerable implementation that demonstrates several of these issues:
app.get('/api/user/:id', (req, res) => {
const token = req.headers.authorization?.replace('Bearer ', '');
// No token validation - accepts any bearer token format
if (!token) {
return res.status(401).json({ error: 'Missing token' });
}
// No expiration check
// No signature verification
// No scope validation
// Directly uses token from query parameter if present
const userId = req.params.id || req.query.userId;
// No authorization check - assumes token owner is requesting their own data
const user = users.find(u => u.id === userId);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
res.json(user);
});
This code accepts any bearer token, doesn't validate its authenticity, and doesn't check whether the token holder has permission to access the requested user data. An attacker could simply change the user ID in the URL to access any user's data.
Bearer Tokens-Specific Detection
Detecting broken authentication in bearer token implementations requires examining both the token validation logic and the authorization controls around protected resources. The most effective approach combines static analysis of the authentication code with dynamic testing of the API's behavior.
Static analysis should focus on token validation code. Look for implementations that accept tokens without verifying their signature, checking expiration, or validating scopes. Common red flags include:
- Direct string comparisons without cryptographic verification
- Missing expiration checks in token validation middleware
- Hardcoded or default secret keys
- Accepting tokens from multiple sources without proper validation
Dynamic testing involves attempting to access protected resources with various token manipulations. Try expired tokens, tokens with modified payloads, tokens intended for different services, and completely invalid tokens. A properly implemented API should reject all of these attempts with appropriate error messages.
Automated scanning tools like middleBrick can systematically test for broken authentication by:
- Submitting requests with malformed or missing tokens
- Testing token replay scenarios
- Checking for token exposure in URLs and logs
- Verifying proper scope validation for different operations
middleBrick's authentication scanning specifically targets bearer token vulnerabilities by testing the unauthenticated attack surface. It attempts to access protected endpoints without tokens, with invalid tokens, and with tokens that have insufficient permissions. The scanner then reports on which endpoints are vulnerable to unauthorized access.
Network-level detection is also important. Monitor for tokens being sent in URLs, being logged in plaintext, or being transmitted over non-HTTPS connections. Tools like Wireshark or browser developer tools can help identify these exposures during testing.
API specification analysis can reveal authentication gaps. When examining OpenAPI/Swagger specifications, look for:
- Missing authentication requirements on sensitive endpoints
- Inconsistent security scheme definitions
- Missing scope definitions for operations
Here's how you might use middleBrick to scan for broken authentication in a bearer token API:
# Install the CLI tool
npm install -g middlebrick
# Scan a bearer token API endpoint
middlebrick scan https://api.example.com/user/profile --output json
# Scan with specific focus on authentication vulnerabilities
middlebrick scan https://api.example.com --tests authentication --output detailed
The scanner will test various authentication bypass techniques and report on the API's resistance to common bearer token attacks. It checks whether the API properly validates tokens, enforces proper authorization, and protects against token replay and fixation attacks.
Bearer Tokens-Specific Remediation
Fixing broken authentication in bearer token implementations requires a multi-layered approach that addresses token validation, authorization, and secure transmission. The foundation is implementing proper token validation using industry-standard libraries rather than custom implementations.
For JWT tokens (the most common bearer token format), use well-vetted libraries like jsonwebtoken in Node.js or PyJWT in Python. These libraries handle signature verification, expiration checks, and algorithm validation correctly. Never implement your own JWT parsing or verification logic.
Here's a secure implementation pattern:
const jwt = require('jsonwebtoken');
const authMiddleware = async (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Missing or malformed token' });
}
const token = authHeader.substring(7);
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256', 'RS256'],
issuer: 'your-issuer',
audience: 'your-audience'
});
// Store decoded token for downstream use
req.user = decoded;
next();
} catch (err) {
if (err.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'Token expired' });
}
if (err.name === 'JsonWebTokenError') {
return res.status(401).json({ error: 'Invalid token' });
}
return res.status(401).json({ error: 'Authentication failed' });
}
};
// Use the middleware on protected routes
app.get('/api/user/profile', authMiddleware, (req, res) => {
// req.user is now available with verified token data
res.json({
userId: req.user.sub,
email: req.user.email,
permissions: req.user.permissions
});
});
This implementation properly verifies the token signature, checks expiration, validates the issuer and audience, and rejects malformed tokens. It also provides specific error messages that don't leak information about why authentication failed.
Authorization should be handled separately from authentication. After verifying the token, check whether the token holder has permission to access the specific resource they're requesting. This prevents horizontal privilege escalation where users can access other users' data.
const authorizeUser = (req, res, next) => {
const { userId } = req.params;
const authenticatedUserId = req.user.sub;
// Check if user is accessing their own data or has admin privileges
if (userId !== authenticatedUserId && !req.user.isAdmin) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
next();
};
// Chain authentication and authorization
app.get('/api/user/:userId', authMiddleware, authorizeUser, (req, res) => {
const user = users.find(u => u.id === req.params.userId);
res.json(user);
});
Implement token rotation and refresh mechanisms to limit the impact of token theft. Short-lived access tokens (5-15 minutes) combined with refresh tokens that can obtain new access tokens reduce the window of opportunity for attackers.
Always transmit tokens over HTTPS to prevent interception. Never send bearer tokens in URLs, and configure servers to avoid logging Authorization headers. Use HTTP-only, secure cookies if storing tokens client-side, and implement proper CSRF protection for cookie-based authentication.
Consider implementing additional security controls like IP binding, device fingerprinting, or anomaly detection to identify suspicious token usage patterns. These controls can help detect and prevent token replay attacks even when the token itself is valid.
Finally, implement proper token revocation mechanisms. Maintain a token blacklist or use short expiration times with refresh tokens so you can quickly invalidate tokens when users log out or when you suspect compromise.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |