async def test_register_login_me_refresh_logout(client, seeded): # Register resp = await client.post( "/api/auth/register", json={ "email": "alice@example.com", "password": "secret123", "full_name": "Alice", }, ) assert resp.status_code == 201, resp.text assert resp.json()["email"] == "alice@example.com" # Login (OAuth2 form: username == email) resp = await client.post( "/api/auth/login", data={"username": "alice@example.com", "password": "secret123"}, ) assert resp.status_code == 200, resp.text tokens = resp.json() access, refresh = tokens["access_token"], tokens["refresh_token"] # /me with bearer token resp = await client.get( "/api/users/me", headers={"Authorization": f"Bearer {access}"} ) assert resp.status_code == 200 assert resp.json()["email"] == "alice@example.com" # Refresh rotates tokens resp = await client.post("/api/auth/refresh", json={"refresh_token": refresh}) assert resp.status_code == 200, resp.text new_refresh = resp.json()["refresh_token"] assert new_refresh != refresh # Old refresh token is now revoked resp = await client.post("/api/auth/refresh", json={"refresh_token": refresh}) assert resp.status_code == 401 # Logout (revokes all) then the rotated refresh token is dead too relogin = await client.post( "/api/auth/login", data={"username": "alice@example.com", "password": "secret123"}, ) new_access = relogin.json()["access_token"] resp = await client.post( "/api/auth/logout", json={}, headers={"Authorization": f"Bearer {new_access}"}, ) assert resp.status_code == 204 resp = await client.post("/api/auth/refresh", json={"refresh_token": new_refresh}) assert resp.status_code == 401 async def test_login_wrong_password(client, seeded): await client.post( "/api/auth/register", json={"email": "bob@example.com", "password": "secret123"}, ) resp = await client.post( "/api/auth/login", data={"username": "bob@example.com", "password": "wrong"}, ) assert resp.status_code == 401 async def test_me_requires_auth(client): assert (await client.get("/api/users/me")).status_code == 401