"""Unit tests for JWT handling and the auth endpoints.""" import datetime import jwt import pytest import auth from config import JWT_SECRET # --- JWT -------------------------------------------------------------------- class TestTokens: def test_sign_and_verify_roundtrip(self): token = auth.sign_token("user-123") assert auth.verify_token(token) == {"user_id": "user-123"} def test_expired_token_rejected(self): past = datetime.datetime.utcnow() - datetime.timedelta(days=1) token = jwt.encode( {"sub": "u", "iat": past, "exp": past}, JWT_SECRET, algorithm="HS256" ) with pytest.raises(jwt.ExpiredSignatureError): auth.verify_token(token) def test_token_signed_with_other_secret_rejected(self): token = jwt.encode({"sub": "u"}, "a-different-secret", algorithm="HS256") with pytest.raises(jwt.InvalidTokenError): auth.verify_token(token) def test_tampered_token_rejected(self): token = auth.sign_token("user-123") head, payload, sig = token.split(".") with pytest.raises(jwt.InvalidTokenError): auth.verify_token(f"{head}.{payload}.{sig[:-2]}xx") # --- require_auth ----------------------------------------------------------- class TestRequireAuth: def test_missing_header(self, client): assert client.get("/api/health/summary").status_code == 401 @pytest.mark.parametrize( "header", ["", "Bearer", "Token abc", "bearer abc", "Bearer not.a.jwt"], ) def test_malformed_headers(self, client, header): r = client.get("/api/health/summary", headers={"Authorization": header}) assert r.status_code == 401 def test_expired_token_gets_401_not_500(self, client): past = datetime.datetime.utcnow() - datetime.timedelta(days=1) token = jwt.encode( {"sub": "u", "iat": past, "exp": past}, JWT_SECRET, algorithm="HS256" ) r = client.get( "/api/health/summary", headers={"Authorization": f"Bearer {token}"} ) assert r.status_code == 401 assert "expired" in r.get_json()["error"] def test_valid_token_passes(self, client, auth): assert client.get("/api/health/summary", headers=auth).status_code == 200 class TestLogoutAndRefresh: def test_logout_clears_stored_token(self, client, auth, user, db): assert client.post("/api/auth/logout", headers=auth).status_code == 200 row = db.query_one("SELECT jwt_token FROM users WHERE id = ?", [user["id"]]) assert row["jwt_token"] is None def test_refresh_returns_usable_token(self, client, auth): r = client.post("/api/auth/refresh", headers=auth) assert r.status_code == 200 new_token = r.get_json()["token"] assert ( client.get( "/api/health/summary", headers={"Authorization": f"Bearer {new_token}"}, ).status_code == 200 ) def test_refresh_requires_auth(self, client): assert client.post("/api/auth/refresh").status_code == 401