unslothai/unsloth · error · HTTPException
Invalid or expired token
Error message
Invalid or expired token
What it means
HTTP 401 raised in _get_secret_for_subject when get_jwt_secret(subject) returns None, i.e. no per-user JWT signing secret is registered for the token's subject. The JWT layer signs each user's tokens with a server-side secret tied to that user; an unknown subject therefore cannot be verified and the token is treated as invalid or expired.
Source
Thrown at studio/backend/auth/authentication.py:33
get_jwt_secret,
get_user_and_secret,
load_jwt_secret,
save_refresh_token,
validate_api_key_with_credential,
verify_refresh_token,
)
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60
REFRESH_TOKEN_EXPIRE_DAYS = 7
security = HTTPBearer() # Reads Authorization: Bearer <token>
def _get_secret_for_subject(subject: str) -> str:
secret = get_jwt_secret(subject)
if secret is None:
raise HTTPException(
status_code = status.HTTP_401_UNAUTHORIZED,
detail = "Invalid or expired token",
)
return secret
def _decode_subject_without_verification(token: str) -> Optional[str]:
try:
payload = jwt.decode(
token,
options = {"verify_signature": False, "verify_exp": False},
)
except jwt.InvalidTokenError:
return None
subject = payload.get("sub")
return subject if isinstance(subject, str) else None
View on GitHub (pinned to 203007d190)
Solutions
- Have the client discard the stored token and re-authenticate (log in again) to obtain a freshly signed token.
- If the user account was deleted/recreated, confirm the subject in the new token matches the current username.
- Operators: verify the JWT secret store is populated for existing users after upgrades or DB resets.
Example fix
// before
fetch('/api/...', { headers: { Authorization: `Bearer ${oldToken}` } });
// after
fetch('/api/...', { headers: { Authorization: `Bearer ${oldToken}` } }).catch(r => { if (r.status === 401) { logout(); login(); } }); Defensive patterns
Strategy: try-catch
Try / catch
try:
resp = client.get('/api/...')
except HTTPStatusError as e:
if e.response.status_code == 401 and 'Invalid or expired token' in e.response.text:
token = login(...) # re-authenticate and retry once Prevention
- Treat any 401 with this detail as 'clear stored token and re-login'.
- Refresh tokens proactively before expiry rather than after a 401.
- After backend DB resets or user recreation, expect old tokens to fail this way.
When it happens
Trigger: Presenting a bearer JWT whose 'sub' claim names a user that was deleted or never existed; a token issued before the server switched to per-subject secrets (so no secret is on record); a corrupted or tampered subject claim.
Common situations: Stale login sessions in the browser after the user account was recreated or removed; tokens minted by an older deployment version kept in localStorage; environments where the secret store was reset (fresh DB) while clients still hold old tokens.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invalid token payload
- Invalid or expired API key
- GitHub {endpoint} returned {r.status_code} {r.reason}. Token
- Local (stdio) MCP servers can only be configured from the Un
- Password change required
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/c96bdb47937e52d7.
Report an issue: GitHub.