Identification Failures with Bearer Tokens
How Identification Failures Manifests in Bearer Tokens
Identification failures in Bearer Token authentication occur when an API fails to properly validate the token's authenticity, integrity, and claims before granting access. This is a specific instance of OWASP API2:2023 (Broken Authentication) and often leads to Broken Object Property Authorization (API5:2023). The core issue is the server's trust in a token presented by the client without sufficient verification.
Common attack patterns include:
- Token Substitution: An attacker uses a valid token from a low-privilege user (e.g., a standard user) to access resources or actions belonging to a high-privilege user (admin). This happens when the API does not validate the token's
scope,roles, or custom claims against the required permission for the endpoint. - Expired or Revoked Token Acceptance: The API accepts tokens past their expiration (
expclaim) or after they have been revoked (e.g., after logout). This often occurs when the server only checks the token's format but not its temporal validity or against a revocation list. - Signature Bypass: The server decodes the token (e.g., a JWT) but fails to verify its cryptographic signature. An attacker can modify the token's payload (e.g., change
user_idorrole) and re-encode it without a valid signature, and the server will accept the altered claims. This is akin to CVE-2020-28022 (an information disclosure in a JWT library due to signature bypass). - Algorithm Confusion: The server accepts tokens signed with
none(unsigned) or incorrectly handles key selection (e.g., using the public key as an HMAC secret). An attacker can exploit this to forge tokens. - Missing Audience/Issuer Validation: The token is accepted even if its
aud(audience) oriss(issuer) claims do not match the expected values for the API. This allows tokens issued for a different service or client to be reused.
In code, this often appears as:
// VULNERABLE: Express.js route that decodes but does not verify
app.get('/admin/data', (req, res) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).send('No token');
const decoded = jwt.decode(token); // DANGER: decode only, no verify!
if (decoded.role === 'admin') {
return res.json({ sensitive: 'admin data' });
}
res.status(403).send('Forbidden');
});The jwt.decode() merely base64-decodes the payload without verifying the signature. Any modified token with a forged role claim will be accepted.
Bearer Tokens-Specific Detection
Detecting identification failures requires testing the API's enforcement of token validation. Since middleBrick performs black-box scanning without credentials, it probes the unauthenticated attack surface by sending crafted requests to evaluate the server's behavior.
middleBrick's Authentication and BOLA/IDOR checks (run in parallel) specifically target these failures:
- Signature Verification Test: middleBrick sends a request with a token that has a valid structure but an invalid signature (or
nonealgorithm). If the API returns a 200 OK instead of 401, it indicates signature verification is absent. - Expiration Test: A token with an expired
expclaim is submitted. Acceptance suggests temporal validation is missing. - Privilege Escalation Probe: middleBrick attempts to use a low-privilege token (if any is discovered during scanning) to access admin-only endpoints, testing for inadequate scope/role checks.
- Audience/Issuer Mismatch: Tokens with incorrect
audorissvalues are sent to see if they are rejected.
For example, scanning an endpoint with middleBrick's CLI:
middlebrick scan https://api.example.com/v1/usersThe scanner might return a finding like:
| Check | Severity | Finding |
|---|---|---|
| Authentication | Critical | Bearer token signature not verified. Endpoint accepts tokens with alg=none. |
middleBrick's OpenAPI/Swagger analysis also cross-references the specification's security schemes (e.g., type: http, scheme: bearer) with runtime behavior. If the spec defines a bearer token requirement but the runtime endpoint accepts requests without one or with invalid tokens, it flags a discrepancy.
Bearer Tokens-Specific Remediation
Remediation centers on robust, server-side token validation using the native features of your authentication library. Never trust client-provided tokens; always verify every claim.
1. Enforce Signature Verification
Use your framework's built-in verification method, not decode. For Node.js/Express with jsonwebtoken:
const jwt = require('jsonwebtoken');
app.get('/admin/data', (req, res) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'Missing token' });
// SECURE: verify signature, expiration, audience, issuer
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
audience: 'api.example.com',
issuer: 'auth.example.com',
algorithms: ['RS256'] // specify expected algorithm
});
// Now decoded.role is trustworthy
if (decoded.role !== 'admin') {
return res.status(403).json({ error: 'Insufficient role' });
}
res.json({ sensitive: 'admin data' });
} catch (err) {
// Catches: TokenExpiredError, JsonWebTokenError, NotBeforeError
return res.status(401).json({ error: 'Invalid or expired token' });
}
});2. Validate All Claims
Check exp (expiration), nbf (not before), iat (issued at), aud (audience), and iss (issuer). The jwt.verify method handles exp and nbf automatically; pass audience and issuer options to enforce them.
3. Use Asymmetric Keys for Public APIs
If the API is public (clients hold tokens), use RS256 (RSA) instead of HS256 (HMAC). The server holds the private key to sign; clients only have the public key to verify. This prevents token forgery if the secret is exposed.
4. Implement Token Revocation
For immediate invalidation, maintain a short-lived access token (e.g., 15 minutes) and a long-lived refresh token stored securely (HTTP-only cookie). On logout or compromise, add the token's jti (JWT ID) to a blocklist (e.g., Redis) checked during verification.
// In verification middleware
const token = req.headers.authorization?.split(' ')[1];
const decoded = jwt.decode(token, { complete: true });
if (await redis.get(`blocklist:${decoded.payload.jti}`)) {
return res.status(401).json({ error: 'Token revoked' });
}
// Proceed with jwt.verify...5. Scope-Based Authorization
After verifying the token, map its scope or custom roles claim to the required permission for the endpoint. Use a middleware like express-jwt or passport with strategies that enforce scopes.
middleBrick's reports will highlight missing validations and provide remediation guidance mapped to OWASP and compliance frameworks like PCI-DSS 8.3 (authenticate all access).
Frequently Asked Questions
How does middleBrick detect bearer token validation issues without valid credentials?
alg=none, expired exp, or wrong signature) to your API endpoints. If the API responds with a 200 OK instead of 401/403, it indicates the token validation is absent or broken. This black-box testing reveals what an unauthenticated attacker could discover.What's the most common mistake developers make with bearer tokens?
jwt.decode() (or equivalent) only reads the payload, allowing attackers to modify claims like role or user_id. Always use jwt.verify() with a secret/public key and validate all claims (exp, aud, iss). Never trust client-side data.