{"record":{"id":"7e1981f02acf6620","repo":"affaan-m/ECC","slug":"inactive-user","errorCode":null,"errorMessage":"Inactive user","messagePattern":"Inactive user","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"skills/fastapi-patterns/SKILL.md","lineNumber":216,"sourceCode":"        payload = jwt.decode(token, settings.secret_key, algorithms=[settings.algorithm])\n        subject = payload.get(\"sub\")\n        if subject is None:\n            raise credentials_exception\n        user_id = int(subject)\n    except (JWTError, TypeError, ValueError):\n        raise credentials_exception\n\n    user = await db.get(User, user_id)\n    if user is None:\n        raise credentials_exception\n    return user\n\n\nasync def get_current_active_user(\n    current_user: Annotated[User, Depends(get_current_user)],\n) -> User:\n    if not current_user.is_active:\n        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=\"Inactive user\")\n    return current_user\n\n\nDbDep = Annotated[AsyncSession, Depends(get_db)]\nCurrentUserDep = Annotated[User, Depends(get_current_user)]\nActiveUserDep = Annotated[User, Depends(get_current_active_user)]\n```\n\n---\n\n## Router and Endpoint Design\n\n```python\n# app/routers/users.py\nfrom typing import Annotated\nfrom fastapi import APIRouter, HTTPException, Query, status\nfrom fastapi.security import OAuth2PasswordRequestForm\n","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/skills/fastapi-patterns/SKILL.md#L198-L234","documentation":"FastAPI dependency `get_current_active_user` runs after `get_current_user` has resolved a valid token and user. If `current_user.is_active` is `False`, it raises `HTTPException(403, \"Inactive user\")`. The dependency is exposed as `ActiveUserDep` and used by routes that require an active account (e.g. `GET /me`, `PATCH /{user_id}`).","triggerScenarios":"A user authenticates successfully (valid JWT, user exists) but their `is_active` flag is `False` — admin-disabled, soft-deleted, or not yet email-verified. Any route using `ActiveUserDep` returns 403.","commonSituations":"Disabled account tries to use the API after an admin ban. Email-verification gate uses `is_active=False` until confirmation. JWT was issued before the user was deactivated (token still valid, but the dependency catches it).","solutions":["If you are the user: complete email verification or contact an admin to re-enable the account.","If you are the admin: set `user.is_active = True` in the DB and reissue.","Front-end: on 403 with this detail, route the user to an \"account disabled / verify email\" screen, not the generic login.","If the flag is intentionally `False`-until-verified, gate only the sensitive routes; consider a separate `is_verified` flag so inactive users can still reach `POST /resend-verification`."],"exampleFix":"# before\nif not current_user.is_active:\n    raise HTTPException(status_code=403, detail=\"Inactive user\")\n\n# after — 403 is correct; add a reason so the client can branch\nif not current_user.is_active:\n    raise HTTPException(\n        status_code=403,\n        detail={\"code\": \"inactive_user\", \"message\": \"Account is inactive\", \"reason\": current_user.inactive_reason},\n    )","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"from fastapi import HTTPException\ntry:\n    user = await get_current_active_user(token=token)\nexcept HTTPException as e:\n    if e.status_code == 403 and 'Inactive user' in e.detail:\n        redirect('/account/inactive')\n    raise","preventionTips":["Front-end should branch on 403+inactive detail rather than treating it as a generic auth failure.","Use a separate `is_verified` flag if inactive users must reach verification endpoints.","Invalidate outstanding JWTs when an account is deactivated."],"tags":["fastapi","auth","dependencies","http-403","accounts"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}