From a7f516397687d39bd6b2fc79022880a65dafc518 Mon Sep 17 00:00:00 2001 From: shivam Date: Thu, 26 Feb 2026 03:49:54 -0800 Subject: [PATCH 1/6] added the env flag --- docs/my-website/docs/proxy/config_settings.md | 1 + litellm/__init__.py | 9 +++-- litellm/constants.py | 5 +++ litellm/proxy/auth/auth_checks.py | 7 ++-- litellm/proxy/auth/login_utils.py | 6 ++-- litellm/proxy/management_endpoints/ui_sso.py | 3 +- .../proxy/auth/test_auth_checks.py | 35 +++++++++++++++++-- 7 files changed, 54 insertions(+), 12 deletions(-) diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md index 8dbebad884..dde39bbc0b 100644 --- a/docs/my-website/docs/proxy/config_settings.md +++ b/docs/my-website/docs/proxy/config_settings.md @@ -775,6 +775,7 @@ router_settings: | LITELLM_HOSTED_UI | URL of the hosted UI for LiteLLM | LITELLM_UI_API_DOC_BASE_URL | Optional override for the API Reference base URL (used in sample code/docs) when the admin UI runs on a different host than the proxy. Defaults to `PROXY_BASE_URL` when unset. | LITELLM_UI_PATH | Path to directory for Admin UI files. Used when running with read-only filesystem (e.g., Kubernetes). Default is `/var/lib/litellm/ui` in Docker. +| LITELLM_UI_SESSION_DURATION | Duration for UI login session (username/password, SSO). Format: "30s", "30m", "24h", "7d". Applies to both default and EXPERIMENTAL_UI_LOGIN flows. Default is "24h" | LITELM_ENVIRONMENT | Environment of LiteLLM Instance, used by logging services. Currently only used by DeepEval. | LITELLM_KEY_ROTATION_ENABLED | Enable auto-key rotation for LiteLLM (boolean). Default is false. | LITELLM_KEY_ROTATION_CHECK_INTERVAL_SECONDS | Interval in seconds for how often to run job that auto-rotates keys. Default is 86400 (24 hours). diff --git a/litellm/__init__.py b/litellm/__init__.py index 6e42f2c1ea..f949046e4d 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -12,6 +12,12 @@ warnings.filterwarnings( ### INIT VARIABLES ######################### import threading import os + +# Load .env before any other litellm imports so env vars (e.g. LITELLM_UI_SESSION_DURATION) are available +import dotenv as _dotenv + +_dotenv.load_dotenv() + from typing import ( Callable, List, @@ -74,12 +80,9 @@ from litellm.constants import ( DEFAULT_ALLOWED_FAILS, ) import httpx -import dotenv # register_async_client_cleanup is lazy-loaded and called on first access litellm_mode = os.getenv("LITELLM_MODE", "DEV") # "PRODUCTION", "DEV" -if litellm_mode == "DEV": - dotenv.load_dotenv() #################################################### diff --git a/litellm/constants.py b/litellm/constants.py index b1a0021bcc..41dce4c587 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -1314,6 +1314,11 @@ CLI_JWT_EXPIRATION_HOURS = int( or 24 ) +########################### UI SESSION DURATION ########################### +# Duration for UI login session (username/password, SSO). Format: "30s", "30m", "24h", "7d" +# Applies to both default and EXPERIMENTAL_UI_LOGIN flows +LITELLM_UI_SESSION_DURATION = os.getenv("LITELLM_UI_SESSION_DURATION", "24h") + ########################### DB CRON JOB NAMES ########################### DB_SPEND_UPDATE_JOB_NAME = "db_spend_update_job" PROMETHEUS_EMIT_BUDGET_METRICS_JOB_NAME = "prometheus_emit_budget_metrics" diff --git a/litellm/proxy/auth/auth_checks.py b/litellm/proxy/auth/auth_checks.py index 500a39d945..25ea9bb4f8 100644 --- a/litellm/proxy/auth/auth_checks.py +++ b/litellm/proxy/auth/auth_checks.py @@ -23,12 +23,14 @@ from litellm.caching.dual_cache import LimitedSizeOrderedDict from litellm.constants import ( CLI_JWT_EXPIRATION_HOURS, CLI_JWT_TOKEN_NAME, + LITELLM_UI_SESSION_DURATION, DEFAULT_ACCESS_GROUP_CACHE_TTL, DEFAULT_IN_MEMORY_TTL, DEFAULT_MANAGEMENT_OBJECT_IN_MEMORY_CACHE_TTL, DEFAULT_MAX_RECURSE_DEPTH, EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE, ) +from litellm.litellm_core_utils.duration_parser import duration_in_seconds from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider from litellm.proxy._types import ( RBAC_ROLES, @@ -1884,8 +1886,9 @@ class ExperimentalUIJWTToken: if user_info.user_role is None: raise Exception("User role is required for experimental UI login") - # Calculate expiration time (10 minutes from now) - expiration_time = get_utc_datetime() + timedelta(minutes=10) + # Calculate expiration time from LITELLM_UI_SESSION_DURATION (default 24h) + session_duration_seconds = duration_in_seconds(LITELLM_UI_SESSION_DURATION) + expiration_time = get_utc_datetime() + timedelta(seconds=session_duration_seconds) # Format the expiration time as ISO 8601 string expires = expiration_time.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "+00:00" diff --git a/litellm/proxy/auth/login_utils.py b/litellm/proxy/auth/login_utils.py index 4df773dec2..c7e22516fe 100644 --- a/litellm/proxy/auth/login_utils.py +++ b/litellm/proxy/auth/login_utils.py @@ -12,7 +12,7 @@ from typing import Literal, Optional, cast from fastapi import HTTPException import litellm -from litellm.constants import LITELLM_PROXY_ADMIN_NAME +from litellm.constants import LITELLM_PROXY_ADMIN_NAME, LITELLM_UI_SESSION_DURATION from litellm.proxy._types import ( LiteLLM_UserTable, LitellmUserRoles, @@ -178,7 +178,7 @@ async def authenticate_user( # noqa: PLR0915 request_type="key", **{ "user_role": LitellmUserRoles.PROXY_ADMIN, - "duration": "24hr", + "duration": LITELLM_UI_SESSION_DURATION, "key_max_budget": litellm.max_ui_session_budget, "models": [], "aliases": {}, @@ -264,7 +264,7 @@ async def authenticate_user( # noqa: PLR0915 request_type="key", **{ # type: ignore "user_role": user_role, - "duration": "24hr", + "duration": LITELLM_UI_SESSION_DURATION, "key_max_budget": litellm.max_ui_session_budget, "models": [], "aliases": {}, diff --git a/litellm/proxy/management_endpoints/ui_sso.py b/litellm/proxy/management_endpoints/ui_sso.py index 5a1b31aebb..84e945e888 100644 --- a/litellm/proxy/management_endpoints/ui_sso.py +++ b/litellm/proxy/management_endpoints/ui_sso.py @@ -25,6 +25,7 @@ from litellm._logging import verbose_proxy_logger from litellm._uuid import uuid from litellm.caching import DualCache from litellm.constants import ( + LITELLM_UI_SESSION_DURATION, MAX_SPENDLOG_ROWS_TO_QUERY, MICROSOFT_USER_DISPLAY_NAME_ATTRIBUTE, MICROSOFT_USER_EMAIL_ATTRIBUTE, @@ -2237,7 +2238,7 @@ class SSOAuthenticationHandler: # User might not be already created on first generation of key # But if it is, we want their models preferences default_ui_key_values: Dict[str, Any] = { - "duration": "24hr", + "duration": LITELLM_UI_SESSION_DURATION, "key_max_budget": litellm.max_ui_session_budget, "aliases": {}, "config": {}, diff --git a/tests/test_litellm/proxy/auth/test_auth_checks.py b/tests/test_litellm/proxy/auth/test_auth_checks.py index 1d8d1be58c..fb2f427e44 100644 --- a/tests/test_litellm/proxy/auth/test_auth_checks.py +++ b/tests/test_litellm/proxy/auth/test_auth_checks.py @@ -108,11 +108,40 @@ def test_get_experimental_ui_login_jwt_auth_token_valid(valid_sso_user_defined_v assert token_data["models"] == ["gpt-3.5-turbo"] assert token_data["max_budget"] == litellm.max_ui_session_budget - # Verify expiration time is set and valid + # Verify expiration time is set and valid (uses LITELLM_UI_SESSION_DURATION) + from litellm.constants import LITELLM_UI_SESSION_DURATION + from litellm.litellm_core_utils.duration_parser import duration_in_seconds + assert "expires" in token_data expires = datetime.fromisoformat(token_data["expires"].replace("Z", "+00:00")) - assert expires > get_utc_datetime() - assert expires <= get_utc_datetime() + timedelta(minutes=10) + session_duration_seconds = duration_in_seconds(LITELLM_UI_SESSION_DURATION) + now = get_utc_datetime() + # Allow 2 second buffer for test execution timing + assert expires > now + assert expires <= now + timedelta(seconds=session_duration_seconds + 2) + + +def test_get_experimental_ui_login_jwt_auth_token_respects_session_duration( + valid_sso_user_defined_values, monkeypatch +): + """Test that LITELLM_UI_SESSION_DURATION controls token expiration""" + from litellm.proxy.auth import auth_checks + + monkeypatch.setattr(auth_checks, "LITELLM_UI_SESSION_DURATION", "10m") + + token = ExperimentalUIJWTToken.get_experimental_ui_login_jwt_auth_token( + valid_sso_user_defined_values + ) + decrypted_token = decrypt_value_helper( + token, key="ui_hash_key", exception_type="debug" + ) + assert decrypted_token is not None + token_data = json.loads(decrypted_token) + expires = datetime.fromisoformat(token_data["expires"].replace("Z", "+00:00")) + now = get_utc_datetime() + # Should expire in ~10 minutes (allow 2 second buffer) + assert expires > now + timedelta(minutes=9) + assert expires <= now + timedelta(minutes=10, seconds=2) def test_get_experimental_ui_login_jwt_auth_token_invalid( From f4f834489c438b3bace30b68306431543d3ef81b Mon Sep 17 00:00:00 2001 From: shivam Date: Thu, 26 Feb 2026 04:04:20 -0800 Subject: [PATCH 2/6] added variable for invitation link --- litellm/__init__.py | 3 ++- litellm/proxy/proxy_server.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/litellm/__init__.py b/litellm/__init__.py index f949046e4d..7277f4e7d5 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -16,7 +16,8 @@ import os # Load .env before any other litellm imports so env vars (e.g. LITELLM_UI_SESSION_DURATION) are available import dotenv as _dotenv -_dotenv.load_dotenv() +if os.getenv("LITELLM_MODE", "DEV") == "DEV": + _dotenv.load_dotenv() from typing import ( Callable, diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index 607306f380..2ed40213fb 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -50,6 +50,7 @@ from litellm.constants import ( LITELLM_EMBEDDING_PROVIDERS_SUPPORTING_INPUT_ARRAY_OF_TOKENS, LITELLM_SETTINGS_SAFE_DB_OVERRIDES, LITELLM_UI_ALLOW_HEADERS, + LITELLM_UI_SESSION_DURATION, ) from litellm.litellm_core_utils.litellm_logging import ( _init_custom_logger_compatible_class, @@ -10767,7 +10768,7 @@ async def onboarding(invite_link: str, request: Request): request_type="key", **{ "user_role": user_obj.user_role, - "duration": "24hr", + "duration": LITELLM_UI_SESSION_DURATION, "key_max_budget": litellm.max_ui_session_budget, "models": [], "aliases": {}, From 6974b6de681814801d838a5d026868c27ba2ceb0 Mon Sep 17 00:00:00 2001 From: shivam Date: Thu, 26 Feb 2026 04:13:52 -0800 Subject: [PATCH 3/6] resolved greptile comment --- litellm/proxy/auth/auth_checks.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/litellm/proxy/auth/auth_checks.py b/litellm/proxy/auth/auth_checks.py index 25ea9bb4f8..7c3345343c 100644 --- a/litellm/proxy/auth/auth_checks.py +++ b/litellm/proxy/auth/auth_checks.py @@ -23,14 +23,12 @@ from litellm.caching.dual_cache import LimitedSizeOrderedDict from litellm.constants import ( CLI_JWT_EXPIRATION_HOURS, CLI_JWT_TOKEN_NAME, - LITELLM_UI_SESSION_DURATION, DEFAULT_ACCESS_GROUP_CACHE_TTL, DEFAULT_IN_MEMORY_TTL, DEFAULT_MANAGEMENT_OBJECT_IN_MEMORY_CACHE_TTL, DEFAULT_MAX_RECURSE_DEPTH, EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE, ) -from litellm.litellm_core_utils.duration_parser import duration_in_seconds from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider from litellm.proxy._types import ( RBAC_ROLES, @@ -1886,9 +1884,8 @@ class ExperimentalUIJWTToken: if user_info.user_role is None: raise Exception("User role is required for experimental UI login") - # Calculate expiration time from LITELLM_UI_SESSION_DURATION (default 24h) - session_duration_seconds = duration_in_seconds(LITELLM_UI_SESSION_DURATION) - expiration_time = get_utc_datetime() + timedelta(seconds=session_duration_seconds) + # Experimental UI flow uses shorter 10-min expiry for security (experimental = shorter-lived tokens) + expiration_time = get_utc_datetime() + timedelta(minutes=10) # Format the expiration time as ISO 8601 string expires = expiration_time.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "+00:00" From d276d273c62aa8252bda1876cda85bfcf0d739af Mon Sep 17 00:00:00 2001 From: Shivam Rawat <161387515+shivamrawat1@users.noreply.github.com> Date: Thu, 26 Feb 2026 04:21:35 -0800 Subject: [PATCH 4/6] Update litellm/constants.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- litellm/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/constants.py b/litellm/constants.py index 41dce4c587..60f7dcdb72 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -1316,7 +1316,7 @@ CLI_JWT_EXPIRATION_HOURS = int( ########################### UI SESSION DURATION ########################### # Duration for UI login session (username/password, SSO). Format: "30s", "30m", "24h", "7d" -# Applies to both default and EXPERIMENTAL_UI_LOGIN flows +# Applies to default login flows (not EXPERIMENTAL_UI_LOGIN which uses its own 10-minute expiry) LITELLM_UI_SESSION_DURATION = os.getenv("LITELLM_UI_SESSION_DURATION", "24h") ########################### DB CRON JOB NAMES ########################### From 44557261a3d1e62225e0305838b92974393d3792 Mon Sep 17 00:00:00 2001 From: shivam Date: Thu, 26 Feb 2026 04:24:51 -0800 Subject: [PATCH 5/6] greptile issue --- docs/my-website/docs/proxy/config_settings.md | 2 +- litellm/proxy/auth/auth_checks.py | 2 +- .../proxy/auth/test_auth_checks.py | 18 +++++------------- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md index dde39bbc0b..0362344d7b 100644 --- a/docs/my-website/docs/proxy/config_settings.md +++ b/docs/my-website/docs/proxy/config_settings.md @@ -775,7 +775,7 @@ router_settings: | LITELLM_HOSTED_UI | URL of the hosted UI for LiteLLM | LITELLM_UI_API_DOC_BASE_URL | Optional override for the API Reference base URL (used in sample code/docs) when the admin UI runs on a different host than the proxy. Defaults to `PROXY_BASE_URL` when unset. | LITELLM_UI_PATH | Path to directory for Admin UI files. Used when running with read-only filesystem (e.g., Kubernetes). Default is `/var/lib/litellm/ui` in Docker. -| LITELLM_UI_SESSION_DURATION | Duration for UI login session (username/password, SSO). Format: "30s", "30m", "24h", "7d". Applies to both default and EXPERIMENTAL_UI_LOGIN flows. Default is "24h" +| LITELLM_UI_SESSION_DURATION | Duration for UI login session (username/password, SSO, invitation links). Format: "30s", "30m", "24h", "7d". Does not apply to EXPERIMENTAL_UI_LOGIN flow, which uses a fixed 10-minute expiry for security. Default is "24h" | LITELM_ENVIRONMENT | Environment of LiteLLM Instance, used by logging services. Currently only used by DeepEval. | LITELLM_KEY_ROTATION_ENABLED | Enable auto-key rotation for LiteLLM (boolean). Default is false. | LITELLM_KEY_ROTATION_CHECK_INTERVAL_SECONDS | Interval in seconds for how often to run job that auto-rotates keys. Default is 86400 (24 hours). diff --git a/litellm/proxy/auth/auth_checks.py b/litellm/proxy/auth/auth_checks.py index 7c3345343c..ef6b0ac462 100644 --- a/litellm/proxy/auth/auth_checks.py +++ b/litellm/proxy/auth/auth_checks.py @@ -1884,7 +1884,7 @@ class ExperimentalUIJWTToken: if user_info.user_role is None: raise Exception("User role is required for experimental UI login") - # Experimental UI flow uses shorter 10-min expiry for security (experimental = shorter-lived tokens) + # Experimental UI flow uses fixed 10-min expiry for security (does not use LITELLM_UI_SESSION_DURATION) expiration_time = get_utc_datetime() + timedelta(minutes=10) # Format the expiration time as ISO 8601 string diff --git a/tests/test_litellm/proxy/auth/test_auth_checks.py b/tests/test_litellm/proxy/auth/test_auth_checks.py index fb2f427e44..ad1ad299b2 100644 --- a/tests/test_litellm/proxy/auth/test_auth_checks.py +++ b/tests/test_litellm/proxy/auth/test_auth_checks.py @@ -108,27 +108,19 @@ def test_get_experimental_ui_login_jwt_auth_token_valid(valid_sso_user_defined_v assert token_data["models"] == ["gpt-3.5-turbo"] assert token_data["max_budget"] == litellm.max_ui_session_budget - # Verify expiration time is set and valid (uses LITELLM_UI_SESSION_DURATION) - from litellm.constants import LITELLM_UI_SESSION_DURATION - from litellm.litellm_core_utils.duration_parser import duration_in_seconds - + # Verify expiration time is set and valid (Experimental UI uses fixed 10-min expiry) assert "expires" in token_data expires = datetime.fromisoformat(token_data["expires"].replace("Z", "+00:00")) - session_duration_seconds = duration_in_seconds(LITELLM_UI_SESSION_DURATION) now = get_utc_datetime() # Allow 2 second buffer for test execution timing assert expires > now - assert expires <= now + timedelta(seconds=session_duration_seconds + 2) + assert expires <= now + timedelta(minutes=10, seconds=2) -def test_get_experimental_ui_login_jwt_auth_token_respects_session_duration( - valid_sso_user_defined_values, monkeypatch +def test_get_experimental_ui_login_jwt_auth_token_uses_10_min_expiry( + valid_sso_user_defined_values, ): - """Test that LITELLM_UI_SESSION_DURATION controls token expiration""" - from litellm.proxy.auth import auth_checks - - monkeypatch.setattr(auth_checks, "LITELLM_UI_SESSION_DURATION", "10m") - + """Test that Experimental UI token uses fixed 10-minute expiry (does not use LITELLM_UI_SESSION_DURATION).""" token = ExperimentalUIJWTToken.get_experimental_ui_login_jwt_auth_token( valid_sso_user_defined_values ) From ffb438f3f2f674090f3346a9879758919d39b667 Mon Sep 17 00:00:00 2001 From: shivam Date: Thu, 26 Feb 2026 04:41:07 -0800 Subject: [PATCH 6/6] fix: clarify EXPERIMENTAL_UI_LOGIN ignores LITELLM_UI_SESSION_DURATION, add regression test --- docs/my-website/docs/proxy/cli_sso.md | 4 ++++ litellm/constants.py | 4 ++-- .../proxy/auth/test_auth_checks.py | 23 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/docs/my-website/docs/proxy/cli_sso.md b/docs/my-website/docs/proxy/cli_sso.md index ad0f033f80..a20f8a313d 100644 --- a/docs/my-website/docs/proxy/cli_sso.md +++ b/docs/my-website/docs/proxy/cli_sso.md @@ -52,6 +52,10 @@ LITELLM_CLI_JWT_EXPIRATION_HOURS=48 EXPERIMENTAL_UI_LOGIN="True" litellm --confi - `LITELLM_CLI_JWT_EXPIRATION_HOURS=168` - Tokens expire after 7 days (168 hours) - `LITELLM_CLI_JWT_EXPIRATION_HOURS=720` - Tokens expire after 30 days (720 hours) +:::note[Experimental UI Session] +When `EXPERIMENTAL_UI_LOGIN` is enabled, the **browser UI login** session uses a fixed 10-minute expiry (not configurable). `LITELLM_UI_SESSION_DURATION` applies only to non-experimental flows. +::: + :::tip You can check your current token's age and expiration status using: ```bash diff --git a/litellm/constants.py b/litellm/constants.py index 60f7dcdb72..48f3b049eb 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -1315,8 +1315,8 @@ CLI_JWT_EXPIRATION_HOURS = int( ) ########################### UI SESSION DURATION ########################### -# Duration for UI login session (username/password, SSO). Format: "30s", "30m", "24h", "7d" -# Applies to default login flows (not EXPERIMENTAL_UI_LOGIN which uses its own 10-minute expiry) +# Duration for UI login session (username/password, SSO, invitation links). Format: "30s", "30m", "24h", "7d" +# Does NOT apply to EXPERIMENTAL_UI_LOGIN flow, which intentionally uses a fixed 10-minute expiry for security. LITELLM_UI_SESSION_DURATION = os.getenv("LITELLM_UI_SESSION_DURATION", "24h") ########################### DB CRON JOB NAMES ########################### diff --git a/tests/test_litellm/proxy/auth/test_auth_checks.py b/tests/test_litellm/proxy/auth/test_auth_checks.py index ad1ad299b2..4cdca2d061 100644 --- a/tests/test_litellm/proxy/auth/test_auth_checks.py +++ b/tests/test_litellm/proxy/auth/test_auth_checks.py @@ -136,6 +136,29 @@ def test_get_experimental_ui_login_jwt_auth_token_uses_10_min_expiry( assert expires <= now + timedelta(minutes=10, seconds=2) +def test_experimental_ui_token_ignores_litellm_ui_session_duration( + valid_sso_user_defined_values, +): + """Regression test: LITELLM_UI_SESSION_DURATION must NOT affect Experimental UI token expiry. + Experimental UI intentionally uses fixed 10-min expiry. If this test fails, the constant + was incorrectly wired to the experimental flow.""" + # Default LITELLM_UI_SESSION_DURATION is "24h" - token must still expire in ~10 min + token = ExperimentalUIJWTToken.get_experimental_ui_login_jwt_auth_token( + valid_sso_user_defined_values + ) + decrypted_token = decrypt_value_helper( + token, key="ui_hash_key", exception_type="debug" + ) + assert decrypted_token is not None + token_data = json.loads(decrypted_token) + expires = datetime.fromisoformat(token_data["expires"].replace("Z", "+00:00")) + now = get_utc_datetime() + # Must be ~10 min, NOT 24h. If LITELLM_UI_SESSION_DURATION were incorrectly used, this would fail. + assert expires <= now + timedelta(minutes=11), ( + "Experimental UI must use 10-min expiry, not LITELLM_UI_SESSION_DURATION" + ) + + def test_get_experimental_ui_login_jwt_auth_token_invalid( invalid_sso_user_defined_values, ):