Skip to content

Commit b18d855

Browse files
committed
add tests for new jwt_leeway
1 parent 6e6ddde commit b18d855

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed

tests/test_session.py

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from unittest.mock import Mock, patch
33
import jwt
44
from datetime import datetime, timezone
5+
import time
56

67
from tests.conftest import with_jwks_mock
78
from workos.session import AsyncSession, Session
@@ -394,6 +395,168 @@ def test_refresh_success_with_aud_claim(
394395

395396
assert isinstance(response, RefreshWithSessionCookieSuccessResponse)
396397

398+
@with_jwks_mock
399+
def test_authenticate_with_slightly_expired_jwt_fails_without_leeway(
400+
self, session_constants, mock_user_management
401+
):
402+
# Create a token that's expired by 5 seconds
403+
current_time = int(time.time())
404+
405+
# Create token claims with exp 5 seconds in the past
406+
token_claims = {
407+
**session_constants["TEST_TOKEN_CLAIMS"],
408+
"exp": current_time - 5, # Expired by 5 seconds
409+
"iat": current_time - 60, # Issued 60 seconds ago
410+
}
411+
412+
slightly_expired_token = jwt.encode(
413+
token_claims,
414+
session_constants["PRIVATE_KEY"],
415+
algorithm="RS256",
416+
)
417+
418+
# Prepare sealed session data with the slightly expired token
419+
session_data = Session.seal_data(
420+
{"access_token": slightly_expired_token, "user": session_constants["TEST_USER"]},
421+
session_constants["COOKIE_PASSWORD"],
422+
)
423+
424+
# With default leeway=0, authentication should fail
425+
session = Session(
426+
user_management=mock_user_management,
427+
client_id=session_constants["CLIENT_ID"],
428+
session_data=session_data,
429+
cookie_password=session_constants["COOKIE_PASSWORD"],
430+
jwt_leeway=0,
431+
)
432+
433+
response = session.authenticate()
434+
assert response.authenticated is False
435+
assert response.reason == AuthenticateWithSessionCookieFailureReason.INVALID_JWT
436+
437+
@with_jwks_mock
438+
def test_authenticate_with_slightly_expired_jwt_succeeds_with_leeway(
439+
self, session_constants, mock_user_management
440+
):
441+
# Create a token that's expired by 5 seconds
442+
current_time = int(time.time())
443+
444+
# Create token claims with exp 5 seconds in the past
445+
token_claims = {
446+
**session_constants["TEST_TOKEN_CLAIMS"],
447+
"exp": current_time - 5, # Expired by 5 seconds
448+
"iat": current_time - 60, # Issued 60 seconds ago
449+
}
450+
451+
slightly_expired_token = jwt.encode(
452+
token_claims,
453+
session_constants["PRIVATE_KEY"],
454+
algorithm="RS256",
455+
)
456+
457+
# Prepare sealed session data with the slightly expired token
458+
session_data = Session.seal_data(
459+
{"access_token": slightly_expired_token, "user": session_constants["TEST_USER"]},
460+
session_constants["COOKIE_PASSWORD"],
461+
)
462+
463+
# With leeway=10, authentication should succeed
464+
session = Session(
465+
user_management=mock_user_management,
466+
client_id=session_constants["CLIENT_ID"],
467+
session_data=session_data,
468+
cookie_password=session_constants["COOKIE_PASSWORD"],
469+
jwt_leeway=10, # 10 seconds leeway
470+
)
471+
472+
response = session.authenticate()
473+
assert response.authenticated is True
474+
assert response.session_id == session_constants["TEST_TOKEN_CLAIMS"]["sid"]
475+
476+
@with_jwks_mock
477+
def test_authenticate_with_significantly_expired_jwt_fails_without_leeway(
478+
self, session_constants, mock_user_management
479+
):
480+
# Create a token that's expired by 60 seconds
481+
current_time = int(time.time())
482+
483+
# Create token claims with exp 60 seconds in the past
484+
token_claims = {
485+
**session_constants["TEST_TOKEN_CLAIMS"],
486+
"exp": current_time - 60, # Expired by 60 seconds
487+
"iat": current_time - 120, # Issued 120 seconds ago
488+
}
489+
490+
significantly_expired_token = jwt.encode(
491+
token_claims,
492+
session_constants["PRIVATE_KEY"],
493+
algorithm="RS256",
494+
)
495+
496+
# Prepare sealed session data with the significantly expired token
497+
session_data = Session.seal_data(
498+
{
499+
"access_token": significantly_expired_token,
500+
"user": session_constants["TEST_USER"]
501+
},
502+
session_constants["COOKIE_PASSWORD"],
503+
)
504+
505+
# With default leeway=0, authentication should fail
506+
session = Session(
507+
user_management=mock_user_management,
508+
client_id=session_constants["CLIENT_ID"],
509+
session_data=session_data,
510+
cookie_password=session_constants["COOKIE_PASSWORD"],
511+
jwt_leeway=0,
512+
)
513+
514+
response = session.authenticate()
515+
assert response.authenticated is False
516+
assert response.reason == AuthenticateWithSessionCookieFailureReason.INVALID_JWT
517+
518+
@with_jwks_mock
519+
def test_authenticate_with_significantly_expired_jwt_fails_with_insufficient_leeway(
520+
self, session_constants, mock_user_management
521+
):
522+
# Create a token that's expired by 60 seconds
523+
current_time = int(time.time())
524+
525+
# Create token claims with exp 60 seconds in the past
526+
token_claims = {
527+
**session_constants["TEST_TOKEN_CLAIMS"],
528+
"exp": current_time - 60, # Expired by 60 seconds
529+
"iat": current_time - 120, # Issued 120 seconds ago
530+
}
531+
532+
significantly_expired_token = jwt.encode(
533+
token_claims,
534+
session_constants["PRIVATE_KEY"],
535+
algorithm="RS256",
536+
)
537+
538+
# Prepare sealed session data with the significantly expired token
539+
session_data = Session.seal_data(
540+
{
541+
"access_token": significantly_expired_token,
542+
"user": session_constants["TEST_USER"]
543+
},
544+
session_constants["COOKIE_PASSWORD"],
545+
)
546+
547+
# With leeway=10, authentication should still fail (not enough leeway)
548+
session = Session(
549+
user_management=mock_user_management,
550+
client_id=session_constants["CLIENT_ID"],
551+
session_data=session_data,
552+
cookie_password=session_constants["COOKIE_PASSWORD"],
553+
jwt_leeway=10, # 10 seconds leeway is not enough for 60 seconds expiration
554+
)
555+
556+
response = session.authenticate()
557+
assert response.authenticated is False
558+
assert response.reason == AuthenticateWithSessionCookieFailureReason.INVALID_JWT
559+
397560

398561
class TestAsyncSession(SessionFixtures):
399562
@with_jwks_mock

0 commit comments

Comments
 (0)