Skip to content

Commit a1c5d5e

Browse files
refactor: read session_expiry/iat as raw claims and trust the platform boundary
The signature-verified, Auth0-issued ID token has already been validated upstream (the platform refuses to emit a malformed session_expiry), so the SDK reads it like every other operational claim instead of running a bespoke validator. Removes State.extract_epoch_claim and reads session_expiry/iat with a plain .get() at both extraction sites; the None guards in the ceiling comparison functions still deliver the absent/null "no ceiling" safe default. Production-reachable inputs (absent/null, clean integer) are unchanged; only unreachable malformed values change behavior, now failing closed rather than being silently accepted.
1 parent ec4c45b commit a1c5d5e

3 files changed

Lines changed: 4 additions & 49 deletions

File tree

src/auth0_server_python/auth_server/server_client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -648,8 +648,8 @@ async def complete_interactive_login(
648648
user_claims = UserClaims.parse_obj(user_info)
649649
# authlib populates `userinfo` from parsed ID token claims, so the
650650
# IPSIE session_expiry claim may surface here.
651-
session_expires_at = State.extract_epoch_claim(user_info, "session_expiry")
652-
issued_at = State.extract_epoch_claim(user_info, "iat")
651+
session_expires_at = user_info.get("session_expiry")
652+
issued_at = user_info.get("iat")
653653
elif id_token:
654654
# Fetch JWKS for signature verification
655655
jwks = await self._get_jwks_cached(origin_domain, metadata)
@@ -667,8 +667,8 @@ async def complete_interactive_login(
667667

668668
user_claims = UserClaims.parse_obj(claims)
669669
# IPSIE session_expiry ceiling from the verified ID token.
670-
session_expires_at = State.extract_epoch_claim(claims, "session_expiry")
671-
issued_at = State.extract_epoch_claim(claims, "iat")
670+
session_expires_at = claims.get("session_expiry")
671+
issued_at = claims.get("iat")
672672
except ValueError as e:
673673
raise ApiError("jwks_key_not_found", str(e))
674674
except jwt.InvalidSignatureError as e:

src/auth0_server_python/tests/test_server_client.py

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4824,30 +4824,6 @@ async def _fake_fetch(self, domain):
48244824
# =============================================================================
48254825

48264826

4827-
def test_extract_epoch_claim_valid():
4828-
assert State.extract_epoch_claim({"session_expiry": 1893456000}, "session_expiry") == 1893456000
4829-
4830-
4831-
def test_extract_epoch_claim_reused_for_iat():
4832-
# Same extractor/validator serves any Unix-seconds claim, e.g. iat.
4833-
assert State.extract_epoch_claim({"iat": 1893456000}, "iat") == 1893456000
4834-
4835-
4836-
def test_extract_epoch_claim_absent_or_empty():
4837-
assert State.extract_epoch_claim(None, "session_expiry") is None
4838-
assert State.extract_epoch_claim({}, "session_expiry") is None
4839-
assert State.extract_epoch_claim({"session_expiry": None}, "session_expiry") is None
4840-
4841-
4842-
def test_extract_epoch_claim_rejects_non_int_and_non_positive():
4843-
# bool is an int subclass but must be rejected
4844-
assert State.extract_epoch_claim({"session_expiry": True}, "session_expiry") is None
4845-
assert State.extract_epoch_claim({"session_expiry": "1893456000"}, "session_expiry") is None
4846-
assert State.extract_epoch_claim({"session_expiry": 1893456000.0}, "session_expiry") is None
4847-
assert State.extract_epoch_claim({"session_expiry": 0}, "session_expiry") is None
4848-
assert State.extract_epoch_claim({"session_expiry": -5}, "session_expiry") is None
4849-
4850-
48514827
def test_is_session_ceiling_reached_none_never_expires():
48524828
assert State.is_session_ceiling_reached(None) is False
48534829

src/auth0_server_python/utils/helpers.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -189,27 +189,6 @@ def update_state_data_for_connection_token_set(
189189
"connection_token_sets": connection_token_sets
190190
}
191191

192-
@classmethod
193-
def extract_epoch_claim(cls, claims: Optional[dict[str, Any]], name: str) -> Optional[int]:
194-
"""
195-
Read a Unix-seconds claim (e.g. `session_expiry`, `iat`) from decoded ID
196-
token claims, or None when absent or invalid.
197-
198-
The value must be a positive JSON integer; non-integer or non-positive
199-
values are rejected rather than trusted.
200-
"""
201-
if not claims:
202-
return None
203-
value = claims.get(name)
204-
if value is None:
205-
return None
206-
# bool is an int subclass — exclude it explicitly.
207-
if isinstance(value, bool) or not isinstance(value, int):
208-
return None
209-
if value <= 0:
210-
return None
211-
return value
212-
213192
@classmethod
214193
def is_session_ceiling_reached(cls, session_expires_at: Optional[int]) -> bool:
215194
"""

0 commit comments

Comments
 (0)