diff --git a/docs/usage/dependency-callables.md b/docs/usage/dependency-callables.md index a74b4240..00399431 100644 --- a/docs/usage/dependency-callables.md +++ b/docs/usage/dependency-callables.md @@ -11,7 +11,7 @@ Return a dependency callable to retrieve currently authenticated user, passing t * `optional`: If `True`, `None` is returned if there is no authenticated user or if it doesn't pass the other requirements. Otherwise, throw `401 Unauthorized`. Defaults to `False`. * `active`: If `True`, throw `401 Unauthorized` if the authenticated user is inactive. Defaults to `False`. -* `verified`: If `True`, throw `401 Unauthorized` if the authenticated user is not verified. Defaults to `False`. +* `verified`: If `True`, throw `403 Forbidden` if the authenticated user is not verified. Defaults to `False`. * `superuser`: If `True`, throw `403 Forbidden` if the authenticated user is not a superuser. Defaults to `False`. ### Examples @@ -88,7 +88,7 @@ def protected_route(user: User = Depends(fastapi_users.get_current_active_user)) ### `get_current_verified_user` -Get the current active and verified user. Will throw a `401 Unauthorized` if missing or wrong credentials or if the user is not active and verified. +Get the current active and verified user. Will throw a `401 Unauthorized` if missing or wrong credentials or if the user is not active. Will throw a `403 Forbidden` if the user is unverified. ```py @app.get("/protected-route") diff --git a/fastapi_users/authentication/__init__.py b/fastapi_users/authentication/__init__.py index 41c8eb38..57b5a1c1 100644 --- a/fastapi_users/authentication/__init__.py +++ b/fastapi_users/authentication/__init__.py @@ -183,12 +183,13 @@ class Authenticator: status_code = status.HTTP_401_UNAUTHORIZED if user: + status_code = status.HTTP_403_FORBIDDEN if active and not user.is_active: + status_code = status.HTTP_401_UNAUTHORIZED user = None elif verified and not user.is_verified: user = None elif superuser and not user.is_superuser: - status_code = status.HTTP_403_FORBIDDEN user = None if not user and not optional: diff --git a/tests/test_fastapi_users.py b/tests/test_fastapi_users.py index a545caa5..217c4c03 100644 --- a/tests/test_fastapi_users.py +++ b/tests/test_fastapi_users.py @@ -191,7 +191,7 @@ class TestGetCurrentVerifiedUser: "/current-verified-user", headers={"Authorization": f"Bearer {user.id}"}, ) - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN async def test_valid_token_verified_user( self, test_app_client: httpx.AsyncClient, verified_user: UserDB @@ -253,7 +253,7 @@ class TestGetCurrentVerifiedSuperuser: "/current-verified-superuser", headers={"Authorization": f"Bearer {user.id}"}, ) - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN async def test_valid_token_verified_user( self, test_app_client: httpx.AsyncClient, verified_user: UserDB @@ -271,7 +271,7 @@ class TestGetCurrentVerifiedSuperuser: "/current-verified-superuser", headers={"Authorization": f"Bearer {superuser.id}"}, ) - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN async def test_valid_token_verified_superuser( self, test_app_client: httpx.AsyncClient, verified_superuser: UserDB diff --git a/tests/test_router_auth.py b/tests/test_router_auth.py index 21a05214..2552f5f1 100644 --- a/tests/test_router_auth.py +++ b/tests/test_router_auth.py @@ -183,7 +183,7 @@ class TestLogout: path, headers={"Authorization": f"Bearer {user.id}"} ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_200_OK diff --git a/tests/test_router_users.py b/tests/test_router_users.py index eec2d51e..350ff696 100644 --- a/tests/test_router_users.py +++ b/tests/test_router_users.py @@ -97,7 +97,7 @@ class TestMe: "/me", headers={"Authorization": f"Bearer {user.id}"} ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_200_OK data = cast(Dict[str, Any], response.json()) @@ -159,7 +159,7 @@ class TestUpdateMe: headers={"Authorization": f"Bearer {user.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN assert after_update.called is False else: assert response.status_code == status.HTTP_400_BAD_REQUEST @@ -181,7 +181,7 @@ class TestUpdateMe: headers={"Authorization": f"Bearer {user.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN assert after_update.called is False else: assert response.status_code == status.HTTP_400_BAD_REQUEST @@ -204,7 +204,7 @@ class TestUpdateMe: "/me", json={}, headers={"Authorization": f"Bearer {user.id}"} ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN assert after_update.called is False else: assert response.status_code == status.HTTP_200_OK @@ -232,7 +232,7 @@ class TestUpdateMe: "/me", json=json, headers={"Authorization": f"Bearer {user.id}"} ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN assert after_update.called is False else: assert response.status_code == status.HTTP_200_OK @@ -260,7 +260,7 @@ class TestUpdateMe: "/me", json=json, headers={"Authorization": f"Bearer {user.id}"} ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN assert after_update.called is False else: assert response.status_code == status.HTTP_200_OK @@ -288,7 +288,7 @@ class TestUpdateMe: "/me", json=json, headers={"Authorization": f"Bearer {user.id}"} ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN assert after_update.called is False else: assert response.status_code == status.HTTP_200_OK @@ -316,7 +316,7 @@ class TestUpdateMe: "/me", json=json, headers={"Authorization": f"Bearer {user.id}"} ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN assert after_update.called is False else: assert response.status_code == status.HTTP_200_OK @@ -349,7 +349,7 @@ class TestUpdateMe: "/me", json=json, headers={"Authorization": f"Bearer {user.id}"} ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN assert after_update.called is False else: assert response.status_code == status.HTTP_200_OK @@ -535,8 +535,6 @@ class TestGetUser: headers={"Authorization": f"Bearer {user.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED - else: assert response.status_code == status.HTTP_403_FORBIDDEN async def test_verified_user( @@ -562,7 +560,7 @@ class TestGetUser: headers={"Authorization": f"Bearer {superuser.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_404_NOT_FOUND @@ -589,7 +587,7 @@ class TestGetUser: f"/{user.id}", headers={"Authorization": f"Bearer {superuser.id}"} ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_200_OK @@ -633,8 +631,6 @@ class TestUpdateUser: headers={"Authorization": f"Bearer {user.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED - else: assert response.status_code == status.HTTP_403_FORBIDDEN async def test_verified_user( @@ -661,7 +657,7 @@ class TestUpdateUser: headers={"Authorization": f"Bearer {superuser.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_404_NOT_FOUND @@ -689,7 +685,7 @@ class TestUpdateUser: f"/{user.id}", json={}, headers={"Authorization": f"Bearer {superuser.id}"} ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_200_OK @@ -727,7 +723,7 @@ class TestUpdateUser: headers={"Authorization": f"Bearer {superuser.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_200_OK @@ -808,7 +804,7 @@ class TestUpdateUser: headers={"Authorization": f"Bearer {superuser.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_200_OK @@ -847,7 +843,7 @@ class TestUpdateUser: headers={"Authorization": f"Bearer {superuser.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_200_OK @@ -886,7 +882,7 @@ class TestUpdateUser: headers={"Authorization": f"Bearer {superuser.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_200_OK @@ -930,7 +926,7 @@ class TestUpdateUser: headers={"Authorization": f"Bearer {superuser.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_200_OK assert mock_user_db.update.called is True @@ -982,8 +978,6 @@ class TestDeleteUser: headers={"Authorization": f"Bearer {user.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED - else: assert response.status_code == status.HTTP_403_FORBIDDEN async def test_verified_user( @@ -1009,7 +1003,7 @@ class TestDeleteUser: headers={"Authorization": f"Bearer {superuser.id}"}, ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_404_NOT_FOUND @@ -1040,7 +1034,7 @@ class TestDeleteUser: f"/{user.id}", headers={"Authorization": f"Bearer {superuser.id}"} ) if requires_verification: - assert response.status_code == status.HTTP_401_UNAUTHORIZED + assert response.status_code == status.HTTP_403_FORBIDDEN else: assert response.status_code == status.HTTP_204_NO_CONTENT assert response.content == b""