ruvnet/RuView · error · HTTPException
Invalid token
Error message
Invalid token
What it means
HTTP 401 raised from the catch-all jwt.JWTError handler in verify_token. It means the token failed cryptographic validation outright: bad signature (secret_key or algorithm mismatch), malformed token, or a decode error -- as opposed to a missing 'sub' or an expired signature, which have their own handlers.
Source
Thrown at plans/phase2-architecture/api-architecture.md:1586
scopes = payload.get('scopes', [])
if user_id is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
return {'user_id': user_id, 'scopes': scopes}
except jwt.ExpiredSignatureError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token has expired",
headers={"WWW-Authenticate": "Bearer"},
)
except jwt.JWTError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token",
headers={"WWW-Authenticate": "Bearer"},
)
def require_scopes(self, required_scopes: List[str]):
"""Decorator to require specific scopes"""
async def scope_checker(token_data: dict = Depends(self.verify_token)):
user_scopes = token_data.get('scopes', [])
for scope in required_scopes:
if scope not in user_scopes:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Not enough permissions. Required scope: {scope}"
)
return token_dataView on GitHub (pinned to 4685618388)
Solutions
- Align secret_key and algorithm between the token issuer and this verifier (check env/config on both sides)
- Confirm the client sends 'Authorization: Bearer <jwt>' with the full three-part token and no whitespace corruption
- Re-login to get a token minted by the same authority the server trusts
- If multiple issuers are legitimate, extend verify_token to try per-issuer keys/algorithms explicitly
Example fix
# before
auth = JWTAuth(secret_key=getenv('JWT_SECRET'), algorithm='HS256') # issuer signs RS256 elsewhere
# after
auth = JWTAuth(secret_key=getenv('JWT_SECRET'), algorithm='HS256')
# issuer must sign with the same secret+algorithm:
token = jwt.encode({'sub': user_id, 'scopes': scopes, 'exp': exp}, getenv('JWT_SECRET'), algorithm='HS256') Defensive patterns
Strategy: try-catch
Validate before calling
import jwt
token = token.removeprefix('Bearer ').strip()
jwt.decode(token, secret_key, algorithms=['HS256']) # local canary: fails fast with the same class of error Try / catch
try:
result = await call_api(token)
except HTTPException as e:
if e.status_code == 401 and e.detail == 'Invalid token':
token = await login_again() # signature/algorithm mismatch; get a token from this authority
else:
raise Prevention
- Keep secret_key and algorithm identical on issuer and verifier; rotate both together
- Strip 'Bearer ' and whitespace before sending the Authorization header
- Log (at debug) which decode stage failed -- signature vs structure -- to speed up diagnosis
When it happens
Trigger: Token signed with a different secret than self.secret_key; token algorithm differs from self.algorithm (e.g. token is RS256 but server expects HS256); corrupted/truncated Authorization header; a non-JWT string passed after the Bearer prefix.
Common situations: Secret rotated on the issuer but not the API (or vice versa); environment drift between dev/prod secrets; alg-confusion tokens from a different IdP; proxy or client mangling the header.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invalid authentication credentials
- Token has expired
- JWT authentication is not configured. In development mode, e
- Authentication required
- Missing or invalid Authorization header
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/3b2f936ffbcafc9d.
Report an issue: GitHub.