{"record":{"id":"0e01e3a84dde6f99","repo":"OpenBB-finance/OpenBB","slug":"invalid-username-or-password","errorCode":null,"errorMessage":"Invalid username or password.","messagePattern":"Invalid username or password\\.","errorType":"http","errorClass":"ValueError","httpStatus":401,"severity":"error","filePath":"openbb_platform/extensions/mcp_server/openbb_mcp_server/app/auth.py","lineNumber":65,"sourceCode":"\n        try:\n            scheme, token = auth_header.split()\n            if scheme.lower() != \"bearer\":\n                raise ValueError(\"Invalid authentication scheme.\")\n\n            try:\n                decoded = base64.b64decode(token).decode(\"utf-8\")\n                username, password = decoded.split(\":\", 1)\n            except (binascii.Error, ValueError) as e:\n                raise ValueError(\"Invalid base64-encoded token.\") from e\n\n            expected_username, expected_password = self.server_auth\n\n            is_user_valid = secrets.compare_digest(username, expected_username)\n            is_pass_valid = secrets.compare_digest(password, expected_password)\n\n            if not (is_user_valid and is_pass_valid):\n                raise ValueError(\"Invalid username or password.\")\n\n            request.state.user = {\"username\": username}\n        except (ValueError, HTTPException) as e:\n            detail = getattr(e, \"detail\", str(e))\n            raise HTTPException(\n                status_code=401,\n                detail=detail,\n                headers={\"WWW-Authenticate\": \"Bearer\"},\n            ) from e\n\n        return True\n\n    async def verify_token(self, token: str) -> AccessToken | None:\n        \"\"\"Verify the token.\"\"\"\n        if not self.server_auth:\n            return None\n\n        try:","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/OpenBB-finance/OpenBB/blob/3e071fcc2cd9f891cac6040ae60296dba76dab46/openbb_platform/extensions/mcp_server/openbb_mcp_server/app/auth.py#L47-L83","documentation":"Raised when the base64 token decodes cleanly but the username or password does not match the server_auth credentials, compared with secrets.compare_digest for timing safety. It surfaces as HTTP 401 with this detail. Credentials are wrong or stale — the request format was correct.","triggerScenarios":"Typo in username or password; credentials rotated on the server but the client still caches the old pair; environment-specific credentials (dev vs prod) mixed up; whitespace accidentally included when building the token.","commonSituations":"Stale .env values after a password rotation; CI using expired test credentials; trailing newline in a password read from a file and included in the base64 payload.","solutions":["Verify the exact username/password pair configured as the server's server_auth.","Regenerate the token after fixing credentials, trimming stray whitespace/newlines before encoding.","Rotate/update the client's stored credentials if the server pair changed.","Confirm you are pointing at the intended environment (dev vs prod server_auth)."],"exampleFix":"# before (password with trailing newline from file read)\npw = open(\"pw.txt\").read()  # \"secret\\n\"\n\n# after\npw = open(\"pw.txt\").read().strip()\ntoken = base64.b64encode(f\"{user}:{pw}\".encode()).decode()","handlingStrategy":"retry","validationCode":"def verify_credentials(candidate_user: str, candidate_pass: str, server_auth: tuple[str, str]) -> bool:\n    import secrets\n    u, p = server_auth\n    return secrets.compare_digest(candidate_user.strip(), u) and secrets.compare_digest(candidate_pass.strip(), p)","typeGuard":null,"tryCatchPattern":"for attempt, (user, pw) in enumerate(credential_sources):\n    try:\n        session.headers[\"Authorization\"] = f\"Bearer {make_bearer_token(user, pw)}\"\n        await client.call_tool(\"list_categories\", {})\n        break\n    except Exception as e:\n        if \"Invalid username or password\" not in str(getattr(e, \"detail\", e)) or attempt == len(credential_sources) - 1:\n            raise","preventionTips":["Strip whitespace/newlines from credentials before base64-encoding.","Refresh stored credentials immediately after server-side rotation.","Keep dev and prod credential sets clearly separated in the client config."],"tags":["openbb","mcp","authentication","credentials"],"backgroundTag":null,"analyzedSha":"3e071fcc2cd9f891cac6040ae60296dba76dab46","analyzedAt":"2026-08-14T23:40:48.960Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}