Modified files
storeapi/security.py
--- 
+++ 
@@ -98,6 +98,8 @@
         raise create_unauthorized_exception("Invalid email or password")
     if not verify_password(password, user.password):
         raise create_unauthorized_exception("Invalid email or password")
+    if not user.confirmed:
+        raise create_unauthorized_exception("User has not confirmed email")
     return user
storeapi/tests/test_security.py
--- 
+++ 
@@ -94,11 +94,11 @@
 @pytest.mark.anyio
-async def test_authenticate_user(registered_user: dict):
+async def test_authenticate_user(confirmed_user: dict):
     user = await security.authenticate_user(
-        registered_user["email"], registered_user["password"]
+        confirmed_user["email"], confirmed_user["password"]
     )
-    assert user.email == registered_user["email"]
+    assert user.email == confirmed_user["email"]
 @pytest.mark.anyio
storeapi/tests/conftest.py
--- 
+++ 
@@ -44,6 +44,17 @@
 @pytest.fixture()
-async def logged_in_token(async_client: AsyncClient, registered_user: dict) -> str:
-    response = await async_client.post("/token", json=registered_user)
+async def confirmed_user(registered_user: dict) -> dict:
+    query = (
+        user_table.update()
+        .where(user_table.c.email == registered_user["email"])
+        .values(confirmed=True)
+    )
+    await database.execute(query)
+    return registered_user
+
+
+@pytest.fixture()
+async def logged_in_token(async_client: AsyncClient, confirmed_user: dict) -> str:
+    response = await async_client.post("/token", json=confirmed_user)
     return response.json()["access_token"]
storeapi/tests/routers/test_user.py
--- 
+++ 
@@ -70,7 +70,9 @@
 @pytest.mark.anyio
-async def test_login_user(async_client: AsyncClient, registered_user: dict):
+async def test_login_user_not_confirmed(
+    async_client: AsyncClient, registered_user: dict
+):
     response = await async_client.post(
         "/token",
         json={
@@ -78,4 +80,13 @@
             "password": registered_user["password"],
         },
     )
+    assert response.status_code == 400
+
+
+@pytest.mark.anyio
+async def test_login_user(async_client: AsyncClient, confirmed_user: dict):
+    response = await async_client.post(
+        "/token",
+        json={"email": confirmed_user["email"], "password": confirmed_user["password"]},
+    )
     assert response.status_code == 200
storeapi/tests/routers/test_post.py
                    --- 
+++ 
@@ -53,7 +53,7 @@
 @pytest.mark.anyio
 async def test_create_post(
-    async_client: AsyncClient, registered_user: dict, logged_in_token: str
+    async_client: AsyncClient, confirmed_user: dict, logged_in_token: str
 ):
     body = "Test Post"
@@ -67,16 +67,16 @@
     assert {
         "id": 1,
         "body": body,
-        "user_id": registered_user["id"],
+        "user_id": confirmed_user["id"],
     }.items() <= response.json().items()
 @pytest.mark.anyio
 async def test_create_post_expired_token(
-    async_client: AsyncClient, registered_user: dict, mocker
+    async_client: AsyncClient, confirmed_user: dict, mocker
 ):
     mocker.patch("storeapi.security.access_token_expire_minutes", return_value=-1)
-    token = security.create_access_token(registered_user["email"])
+    token = security.create_access_token(confirmed_user["email"])
     response = await async_client.post(
         "/post",
         json={"body": "Test Post"},
@@ -168,7 +168,7 @@
 async def test_create_comment(
     async_client: AsyncClient,
     created_post: dict,
-    registered_user: dict,
+    confirmed_user: dict,
     logged_in_token: str,
 ):
     body = "Test Comment"
@@ -183,7 +183,7 @@
         "id": 1,
         "body": body,
         "post_id": created_post["id"],
-        "user_id": registered_user["id"],
+        "user_id": confirmed_user["id"],
     }.items() <= response.json().items()