{"id":"3fc278352c08ca17","repo":"tiangolo/fastapi","slug":"incorrect-username-or-password-3fc278","errorCode":null,"errorMessage":"Incorrect username or password","messagePattern":"Incorrect username or password","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"docs_src/security/tutorial003_py310.py","lineNumber":77,"sourceCode":"        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Not authenticated\",\n            headers={\"WWW-Authenticate\": \"Bearer\"},\n        )\n    return user\n\n\nasync def get_current_active_user(current_user: User = Depends(get_current_user)):\n    if current_user.disabled:\n        raise HTTPException(status_code=400, detail=\"Inactive user\")\n    return current_user\n\n\n@app.post(\"/token\")\nasync def login(form_data: OAuth2PasswordRequestForm = Depends()):\n    user_dict = fake_users_db.get(form_data.username)\n    if not user_dict:\n        raise HTTPException(status_code=400, detail=\"Incorrect username or password\")\n    user = UserInDB(**user_dict)\n    hashed_password = fake_hash_password(form_data.password)\n    if not hashed_password == user.hashed_password:\n        raise HTTPException(status_code=400, detail=\"Incorrect username or password\")\n\n    return {\"access_token\": user.username, \"token_type\": \"bearer\"}\n\n\n@app.get(\"/users/me\")\nasync def read_users_me(current_user: User = Depends(get_current_active_user)):\n    return current_user\n","sourceCodeStart":59,"sourceCodeEnd":89,"githubUrl":"https://github.com/tiangolo/fastapi/blob/42a41db11f6882807ac3c057b942178d53b97438/docs_src/security/tutorial003_py310.py#L59-L89","documentation":"Default-parameter twin of error 44: the `/token` handler raises HTTP 400 'Incorrect username or password' when `fake_users_db.get(form_data.username)` is None. Message is shared with the wrong-password branch (line 81) to prevent user enumeration.","triggerScenarios":"`POST /token` form-encoded with `username=<unknown>`. Branch `if not user_dict:` at line 76.","commonSituations":"Username typo; JSON body sent instead of form data so `form_data.username` is empty; user not provisioned; wrong environment.","solutions":["POST as `application/x-www-form-urlencoded` per the OAuth2 password grant.","Use a username that exists in the store.","Remember the same message covers a wrong password (line 81)."],"exampleFix":"# before\ncurl -X POST http://localhost:8000/token -d 'username=ghost&password=x'\n# after\ncurl -X POST http://localhost:8000/token -d 'username=johndoe&password=secret'","handlingStrategy":"try-catch","validationCode":"def is_form_login(username: str, password: str) -> bool:\n    return bool(username) and bool(password)\n# POST with Content-Type: application/x-www-form-urlencoded when True","typeGuard":"def is_credentials_error(resp) -> bool:\n    return getattr(resp, 'status_code', None) in (400, 401) and \\\n           resp.json().get('detail') == 'Incorrect username or password'","tryCatchPattern":"try:\n    tok = client.post('/token', data={'username': u, 'password': p})\n    tok.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.json().get('detail') == 'Incorrect username or password':\n        show_user_friendly_login_error()\n    raise","preventionTips":["Use form encoding for /token, never JSON.","Keep the generic message; do not help attackers enumerate.","Rate-limit login attempts."],"tags":["authentication","oauth2","login","security","fastapi"],"analyzedSha":"42a41db11f6882807ac3c057b942178d53b97438","analyzedAt":"2026-08-04T19:23:32.007Z","schemaVersion":2}