{"record":{"id":"8052400c6890bf1e","repo":"invoke-ai/InvokeAI","slug":"invalid-or-expired-token-805240","errorCode":null,"errorMessage":"Invalid or expired token","messagePattern":"Invalid or expired token","errorType":"http","errorClass":"HTTPException","httpStatus":401,"severity":"error","filePath":"invokeai/app/api/routers/auth.py","lineNumber":322,"sourceCode":"\n    Raises:\n        HTTPException: 401 if the Bearer token is missing, invalid, or expired, or\n        the user no longer exists or is inactive (raised by the auth dependency).\n    \"\"\"\n    config = ApiDependencies.invoker.services.configuration\n    if not config.multiuser:\n        return MediaCookieResponse(success=True)\n\n    # CurrentUserOrDefault has already validated the Bearer token (signature, expiry,\n    # user exists and is active) — in multiuser mode it 401s otherwise, so credentials\n    # cannot be None here. The raw token is still needed as the cookie value.\n    if credentials is None:\n        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=\"Authentication required\")\n\n    token = credentials.credentials\n    remaining = get_token_remaining_seconds(token)\n    if remaining is None:\n        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=\"Invalid or expired token\")\n\n    _set_media_cookie(request, response, token, remaining)\n    return MediaCookieResponse(success=True)\n\n\n@auth_router.get(\"/me\", response_model=UserDTO)\ndef get_current_user_info(\n    current_user: CurrentUser,\n) -> UserDTO:\n    \"\"\"Get current authenticated user's information.\n\n    Args:\n        current_user: The authenticated user's token data\n\n    Returns:\n        UserDTO containing user information\n\n    Raises:","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/api/routers/auth.py#L304-L340","documentation":"After extracting the raw token, refresh_media_cookie calls get_token_remaining_seconds(token); if it returns None the token's signature is invalid or it has expired, so a 401 'Invalid or expired token' is raised and no media cookie is set.","triggerScenarios":"Calling the media-cookie refresh endpoint with a Bearer token that is expired (past TOKEN_EXPIRATION_NORMAL / REMEMBER_ME) or has an invalid signature (e.g. JWT secret changed after restart, token from a different install).","commonSituations":"Long-lived tab/browser session outliving the token TTL; server restarted with a different secret key invalidating old tokens; copying a token between environments; clock skew.","solutions":["Re-authenticate via /auth/login to get a fresh token, then retry","Use remember_me on login for a longer token lifetime (TOKEN_EXPIRATION_REMEMBER_ME)","If tokens break after every restart, configure a stable secret key for the server","Sync server/client clocks if skew is the cause"],"exampleFix":"// before\nawait refreshMediaCookie(staleToken); // 401 invalid or expired\n// after\nconst { access_token } = await api.post('/auth/login', creds);\nawait refreshMediaCookie(access_token);","handlingStrategy":"try-catch","validationCode":"# decode JWT locally to check expiry before the call\nimport time, base64, json\n\ndef token_expired(token: str) -> bool:\n    payload = json.loads(base64.urlsafe_b64decode(token.split('.')[1] + '=='))\n    return payload.get('exp', 0) < time.time()","typeGuard":"def is_fresh_token(token: str) -> bool:\n    import time, base64, json\n    try:\n        payload = json.loads(base64.urlsafe_b64decode(token.split('.')[1] + '=='))\n        return payload.get('exp', 0) >= time.time()\n    except Exception:\n        return False","tryCatchPattern":"try:\n    resp = requests.post(f'{base}/auth/media-cookie', headers={'Authorization': f'Bearer {token}'})\n    resp.raise_for_status()\nexcept requests.HTTPError as e:\n    if e.response.status_code == 401 and 'expired' in e.response.json().get('detail', ''):\n        token = relogin()  # refresh token, then retry once","preventionTips":["Refresh the token proactively before its exp passes (use remember_me for longer TTL)","Set a stable JWT secret so restarts don't invalidate tokens","Wrap authenticated calls in a 401 -> re-login -> retry-once interceptor","Check clock sync if tokens seem to expire early"],"tags":["http-401","jwt","token-expired"],"backgroundTag":"jwt-token-expired","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}