1+ import math
2+
13import pytest
24
35from app .models import User
46from tests import utils
7+ from flask_jwt_extended import decode_token
58
69
710class TestAuth :
811912 TEST_PASSWORD = "testpassword"
13+ ACCESS_TOKEN_DELTA = 10800 # 3 hours in seconds
14+ REFRESH_TOKEN_DELTA = 259200 # 3 days in seconds
1015
1116 @pytest .fixture (autouse = True )
1217 def setup (self , client ):
@@ -41,6 +46,33 @@ def _test_invalid_request_data(self, endpoint, expected_status=400):
4146 response = self .client .post (endpoint , data = "not json data" )
4247 assert response .status_code == 415
4348
49+ def _decode_token (self , token ):
50+ return decode_token (token , allow_expired = False )
51+
52+ def _assert_jwt_structure (self , token , expected_sub , expected_type , fresh = False ):
53+ assert token .count ("." ) == 2 , f"Token does not have three segments: { token } "
54+ payload = self ._decode_token (token )
55+ assert payload ["sub" ] == expected_sub
56+ assert payload ["type" ] == expected_type
57+ assert "iat" in payload
58+ assert "exp" in payload
59+ assert "jti" in payload
60+ assert payload ["fresh" ] is fresh
61+
62+ # Expiry check
63+ expected_delta = None
64+ if expected_type == "access" :
65+ expected_delta = self .ACCESS_TOKEN_DELTA
66+ if expected_type == "refresh" :
67+ expected_delta = self .REFRESH_TOKEN_DELTA
68+
69+ if expected_delta is not None :
70+ actual_delta = payload ["exp" ] - payload ["iat" ]
71+ # Allow a small margin (e.g., 0-2 seconds) for processing time
72+ assert math .isclose (actual_delta , expected_delta , abs_tol = 2 ), (
73+ f"Token expiry delta { actual_delta } != expected { expected_delta } "
74+ )
75+
4476 def test_register_success (self , register_user ):
4577 response = register_user (self .TEST_EMAIL , self .TEST_PASSWORD )
4678
@@ -81,8 +113,9 @@ def test_login_success(self, register_user, login_user):
81113 data = response .get_json ()
82114 assert "access_token" in data
83115 assert "refresh_token" in data
84- assert len (data ["access_token" ]) > 0
85- assert len (data ["refresh_token" ]) > 0
116+
117+ self ._assert_jwt_structure (data ["access_token" ], expected_sub = "1" , expected_type = "access" , fresh = True )
118+ self ._assert_jwt_structure (data ["refresh_token" ], expected_sub = "1" , expected_type = "refresh" )
86119
87120 def test_login_invalid_password (self , register_user , login_user ):
88121 register_user (self .TEST_EMAIL , self .TEST_PASSWORD )
@@ -109,6 +142,8 @@ def test_refresh_token(self, register_user, login_user):
109142 assert data ["access_token" ] != original_access_token
110143 assert "refresh_token" not in data
111144
145+ self ._assert_jwt_structure (data ["access_token" ], expected_sub = "1" , expected_type = "access" , fresh = False )
146+
112147 def test_refresh_token_invalid (self , register_user , login_user ):
113148 # Access token test
114149 register_user (self .TEST_EMAIL , self .TEST_PASSWORD )
0 commit comments