Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-okta for openSUSE:Factory checked in at 2025-05-05 22:28:39 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-okta (Old) and /work/SRC/openSUSE:Factory/.python-okta.new.30101 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-okta" Mon May 5 22:28:39 2025 rev:5 rq:1274397 version:2.9.13 Changes: -------- --- /work/SRC/openSUSE:Factory/python-okta/python-okta.changes 2025-04-29 16:41:29.188977520 +0200 +++ /work/SRC/openSUSE:Factory/.python-okta.new.30101/python-okta.changes 2025-05-05 22:59:30.608325165 +0200 @@ -1,0 +2,8 @@ +Mon May 5 08:02:16 UTC 2025 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- Update to 2.9.13 + * Expire and renew the access token when using OAuth 2.0 +- from version 2.9.12 + * Reduce JWT Token Expiration time + +------------------------------------------------------------------- Old: ---- okta-2.9.11.tar.gz New: ---- okta-2.9.13.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-okta.spec ++++++ --- /var/tmp/diff_new_pack.W8V6Ic/_old 2025-05-05 22:59:31.048343666 +0200 +++ /var/tmp/diff_new_pack.W8V6Ic/_new 2025-05-05 22:59:31.052343834 +0200 @@ -19,7 +19,7 @@ %{?sle15_python_module_pythons} Name: python-okta -Version: 2.9.11 +Version: 2.9.13 Release: 0 Summary: Python SDK for the Okta Management API License: Apache-2.0 ++++++ okta-2.9.11.tar.gz -> okta-2.9.13.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/CHANGELOG.md new/okta-2.9.13/CHANGELOG.md --- old/okta-2.9.11/CHANGELOG.md 2025-04-04 13:19:56.000000000 +0200 +++ new/okta-2.9.13/CHANGELOG.md 2025-04-30 14:31:34.000000000 +0200 @@ -1,5 +1,11 @@ # Okta Python SDK Changelog +## 2.9.13 +* Expire and renew the access token when using OAuth 2.0 + +## 2.9.12 +* Reduce JWT Token Expiration time + ## 2.9.11 * Allow latest aenum release * Add missing OAuthGrantType enum values diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/PKG-INFO new/okta-2.9.13/PKG-INFO --- old/okta-2.9.11/PKG-INFO 2025-04-04 13:20:06.532604200 +0200 +++ new/okta-2.9.13/PKG-INFO 2025-04-30 14:32:17.035027300 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: okta -Version: 2.9.11 +Version: 2.9.13 Summary: Python SDK for the Okta Management API Home-page: https://github.com/okta/okta-sdk-python Author: Okta, Inc. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/okta/__init__.py new/okta-2.9.13/okta/__init__.py --- old/okta-2.9.11/okta/__init__.py 2025-04-04 13:19:56.000000000 +0200 +++ new/okta-2.9.13/okta/__init__.py 2025-04-30 14:31:34.000000000 +0200 @@ -1 +1 @@ -__version__ = '2.9.11' +__version__ = '2.9.13' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/okta/client.py new/okta-2.9.13/okta/client.py --- old/okta-2.9.11/okta/client.py 2025-03-26 10:26:52.000000000 +0100 +++ new/okta-2.9.13/okta/client.py 2025-04-30 13:28:09.000000000 +0200 @@ -116,7 +116,7 @@ client_config_setter = ConfigSetter() client_config_setter._apply_config({'client': user_config}) self._config = client_config_setter.get_config() - # Prune configuration to remove unnecesary fields + # Prune configuration to remove unnecessary fields self._config = client_config_setter._prune_config(self._config) # Validate configuration ConfigValidator(self._config) @@ -128,6 +128,7 @@ self._client_id = None self._scopes = None self._private_key = None + self._oauth_token_renewal_offset = None # Determine which cache to use cache = NoOpCache() @@ -154,6 +155,7 @@ self._client_id = self._config["client"]["clientId"] self._scopes = self._config["client"]["scopes"] self._private_key = self._config["client"]["privateKey"] + self._oauth_token_renewal_offset = self._config["client"]["oauthTokenRenewalOffset"] setup_logging(log_level=self._config["client"]["logging"]["logLevel"]) # Check if logging should be enabled diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/okta/config/config_setter.py new/okta-2.9.13/okta/config/config_setter.py --- old/okta-2.9.11/okta/config/config_setter.py 2025-03-26 10:26:52.000000000 +0100 +++ new/okta-2.9.13/okta/config/config_setter.py 2025-04-30 13:28:09.000000000 +0200 @@ -37,7 +37,8 @@ }, "rateLimit": { "maxRetries": '' - } + }, + "oauthTokenRenewalOffset": '' }, "testing": { "testingDisableHttpsCheck": '' @@ -116,6 +117,7 @@ self._config["client"]["rateLimit"] = { "maxRetries": 2 } + self._config["client"]["oauthTokenRenewalOffset"] = 5 self._config["testing"]["testingDisableHttpsCheck"] = False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/okta/config/config_validator.py new/okta-2.9.13/okta/config/config_validator.py --- old/okta-2.9.11/okta/config/config_validator.py 2025-03-26 10:26:52.000000000 +0100 +++ new/okta-2.9.13/okta/config/config_validator.py 2025-04-30 13:28:09.000000000 +0200 @@ -45,9 +45,8 @@ self._validate_token( client.get('token', "")) elif client.get('authorizationMode') == "PrivateKey": - client_fields = ['clientId', 'scopes', 'privateKey'] - client_fields_values = [self._config.get( - 'client').get(field, "") for field in client_fields] + client_fields = ['clientId', 'scopes', 'privateKey', 'oauthTokenRenewalOffset'] + client_fields_values = [client.get(field, "") for field in client_fields] errors += self._validate_client_fields(*client_fields_values) else: # Not a valid authorization mode errors += [ @@ -61,7 +60,7 @@ f"See {REPO_URL} for usage") def _validate_client_fields(self, client_id, client_scopes, - client_private_key): + client_private_key, oauth_token_renewal_offset): client_fields_errors = [] # check client id @@ -77,6 +76,14 @@ if not (client_scopes and client_private_key): client_fields_errors.append(ERROR_MESSAGE_SCOPES_PK_MISSING) + # Validate oauthTokenRenewalOffset + if not oauth_token_renewal_offset: + client_fields_errors.append("oauthTokenRenewalOffset must be provided") + if not isinstance(oauth_token_renewal_offset, int): + client_fields_errors.append("oauthTokenRenewalOffset must be a valid integer") + if isinstance(oauth_token_renewal_offset, int) and oauth_token_renewal_offset < 0: + client_fields_errors.append("oauthTokenRenewalOffset must be a non-negative integer") + return client_fields_errors def _validate_token(self, token: str): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/okta/jwt.py new/okta-2.9.13/okta/jwt.py --- old/okta-2.9.11/okta/jwt.py 2025-03-26 10:26:52.000000000 +0100 +++ new/okta-2.9.13/okta/jwt.py 2025-04-30 13:28:09.000000000 +0200 @@ -17,7 +17,7 @@ OAUTH_ENDPOINT = "/oauth2/v1/token" HASH_ALGORITHM = "RS256" PEM_FORMAT = "PKCS1" - ONE_HOUR = 1 * 60 * 60 + EXPIRATION = 1 * 60 * 50 JWT_OPTIONS = { 'verify_signature': True, 'verify_aud': True, @@ -116,7 +116,7 @@ my_pem, _ = JWT.get_PEM_JWK(private_key) # Get current time and expiry time for token issued_time = int(time.time()) - expiry_time = issued_time + JWT.ONE_HOUR + expiry_time = issued_time + JWT.EXPIRATION # generate unique JWT ID generated_JWT_ID = str(uuid.uuid4()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/okta/oauth.py new/okta-2.9.13/okta/oauth.py --- old/okta-2.9.11/okta/oauth.py 2025-03-26 10:26:52.000000000 +0100 +++ new/okta-2.9.13/okta/oauth.py 2025-04-30 13:28:09.000000000 +0200 @@ -1,3 +1,4 @@ +import time from urllib.parse import urlencode, quote from okta.jwt import JWT from okta.http_client import HTTPClient @@ -37,6 +38,14 @@ str, Exception: Tuple of the access token, error that was raised (if any) """ + + # Check if access token has expired or will expire soon + current_time = int(time.time()) + if self._access_token and hasattr(self, '_access_token_expiry_time'): + renewal_offset = self._config["client"]["oauthTokenRenewalOffset"] * 60 # Convert minutes to seconds + if current_time + renewal_offset >= self._access_token_expiry_time: + self.clear_access_token() + # Return token if already generated if self._access_token: return (self._access_token, None) @@ -82,6 +91,9 @@ # Otherwise set token and return it self._access_token = parsed_response["access_token"] + + # Set token expiry time + self._access_token_expiry_time = int(time.time()) + parsed_response["expires_in"] return (self._access_token, None) def clear_access_token(self): @@ -91,3 +103,4 @@ self._access_token = None self._request_executor._cache.delete("OKTA_ACCESS_TOKEN") self._request_executor._default_headers.pop("Authorization", None) + self._access_token_expiry_time = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/okta.egg-info/PKG-INFO new/okta-2.9.13/okta.egg-info/PKG-INFO --- old/okta-2.9.11/okta.egg-info/PKG-INFO 2025-04-04 13:20:06.000000000 +0200 +++ new/okta-2.9.13/okta.egg-info/PKG-INFO 2025-04-30 14:32:16.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: okta -Version: 2.9.11 +Version: 2.9.13 Summary: Python SDK for the Okta Management API Home-page: https://github.com/okta/okta-sdk-python Author: Okta, Inc. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/okta.egg-info/SOURCES.txt new/okta-2.9.13/okta.egg-info/SOURCES.txt --- old/okta-2.9.11/okta.egg-info/SOURCES.txt 2025-04-04 13:20:06.000000000 +0200 +++ new/okta-2.9.13/okta.egg-info/SOURCES.txt 2025-04-30 14:32:16.000000000 +0200 @@ -536,9 +536,6 @@ tests/conftest.py tests/mocks.py tests/utils.py -tests/__pycache__/__init__.cpython-312.pyc -tests/__pycache__/conftest.cpython-312-pytest-8.3.5.pyc -tests/__pycache__/mocks.cpython-312.pyc tests/integration/test_applications_it.py tests/integration/test_auth_server_it.py tests/integration/test_authenticators_it.py @@ -760,6 +757,8 @@ tests/unit/test_applications_ut.py tests/unit/test_cache.py tests/unit/test_client.py +tests/unit/test_config_setter.py +tests/unit/test_config_validator.py tests/unit/test_constants.py tests/unit/test_domains.py tests/unit/test_helpers.py @@ -775,25 +774,6 @@ tests/unit/test_user_profile.py tests/unit/test_user_schema.py tests/unit/test_utils.py -tests/unit/__pycache__/test_api_response.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_applications_ut.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_cache.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_client.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_constants.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_domains.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_helpers.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_http_client.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_jwt.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_logger.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_models.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_oauth.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_oauth_clear_access_token.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_request_executor.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_retry_logic.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_sign_on_modes.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_user_profile.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_user_schema.cpython-312-pytest-8.3.5.pyc -tests/unit/__pycache__/test_utils.cpython-312-pytest-8.3.5.pyc tests/unit/cassettes/test_client_error_call_SSWS.yaml tests/unit/cassettes/test_client_error_call_oauth.yaml tests/unit/cassettes/test_client_success_call_SSWS.yaml Binary files old/okta-2.9.11/tests/__pycache__/__init__.cpython-312.pyc and new/okta-2.9.13/tests/__pycache__/__init__.cpython-312.pyc differ Binary files old/okta-2.9.11/tests/__pycache__/conftest.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/__pycache__/conftest.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/__pycache__/mocks.cpython-312.pyc and new/okta-2.9.13/tests/__pycache__/mocks.cpython-312.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_api_response.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_api_response.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_applications_ut.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_applications_ut.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_cache.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_cache.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_client.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_client.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_constants.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_constants.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_domains.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_domains.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_helpers.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_helpers.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_http_client.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_http_client.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_jwt.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_jwt.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_logger.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_logger.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_models.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_models.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_oauth.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_oauth.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_oauth_clear_access_token.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_oauth_clear_access_token.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_request_executor.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_request_executor.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_retry_logic.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_retry_logic.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_sign_on_modes.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_sign_on_modes.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_user_profile.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_user_profile.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_user_schema.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_user_schema.cpython-312-pytest-8.3.5.pyc differ Binary files old/okta-2.9.11/tests/unit/__pycache__/test_utils.cpython-312-pytest-8.3.5.pyc and new/okta-2.9.13/tests/unit/__pycache__/test_utils.cpython-312-pytest-8.3.5.pyc differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/tests/unit/test_client.py new/okta-2.9.13/tests/unit/test_client.py --- old/okta-2.9.11/tests/unit/test_client.py 2025-03-28 06:11:09.000000000 +0100 +++ new/okta-2.9.13/tests/unit/test_client.py 2025-04-30 13:28:09.000000000 +0200 @@ -914,3 +914,17 @@ config = {'orgUrl': org_url, 'token': token} async with OktaClient(config) as client: assert isinstance(client._request_executor._http_client._session, aiohttp.ClientSession) + + +def test_client_initialization(): + config = { + "orgUrl": "https://dev-1dq2.okta.com/oauth2/default", + "authorizationMode": "PrivateKey", + "clientId": "valid-client-id", + "scopes": ["scope1", "scope2"], + "privateKey": "valid-private-key", + "token": "valid-token", + } + client = OktaClient(config) + assert client._config["client"]["orgUrl"] == "https://dev-1dq2.okta.com/oauth2/default" + assert client._config["client"]["clientId"] == "valid-client-id" \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/tests/unit/test_config_setter.py new/okta-2.9.13/tests/unit/test_config_setter.py --- old/okta-2.9.11/tests/unit/test_config_setter.py 1970-01-01 01:00:00.000000000 +0100 +++ new/okta-2.9.13/tests/unit/test_config_setter.py 2025-04-30 13:28:09.000000000 +0200 @@ -0,0 +1,11 @@ +from okta.config.config_setter import ConfigSetter + +""" +Testing Config Setter +""" + +def test_env_variable_application(monkeypatch): + config_setter = ConfigSetter() + config_setter._apply_default_values() + + assert config_setter._config["client"]["oauthTokenRenewalOffset"] == 5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/tests/unit/test_config_validator.py new/okta-2.9.13/tests/unit/test_config_validator.py --- old/okta-2.9.11/tests/unit/test_config_validator.py 1970-01-01 01:00:00.000000000 +0100 +++ new/okta-2.9.13/tests/unit/test_config_validator.py 2025-04-30 13:28:09.000000000 +0200 @@ -0,0 +1,41 @@ +import pytest +from okta.config.config_validator import ConfigValidator + +""" +Testing Config Validator +""" + +def test_validate_config_valid(): + config = { + "client": { + "orgUrl": "https://example.okta.com", + "authorizationMode": "PrivateKey", + "clientId": "valid-client-id", + "scopes": ["scope1", "scope2"], + "privateKey": "valid-private-key", + "oauthTokenRenewalOffset": 5 + }, + "testing": { + "testingDisableHttpsCheck": False + } + } + validator = ConfigValidator(config) + assert validator.validate_config() is None + +def test_validate_config_invalid_org_url(): + config = { + "client": { + "orgUrl": "http://example.okta.com", + "authorizationMode": "PrivateKey", + "clientId": "valid-client-id", + "scopes": ["scope1", "scope2"], + "privateKey": "valid-private-key", + "oauthTokenRenewalOffset": 5 + }, + "testing": { + "testingDisableHttpsCheck": False + } + } + with pytest.raises(ValueError) as excinfo: + ConfigValidator(config) + assert "must start with 'https'." in str(excinfo.value) \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/okta-2.9.11/tests/unit/test_oauth.py new/okta-2.9.13/tests/unit/test_oauth.py --- old/okta-2.9.11/tests/unit/test_oauth.py 2025-03-26 10:26:52.000000000 +0100 +++ new/okta-2.9.13/tests/unit/test_oauth.py 2025-04-30 13:28:09.000000000 +0200 @@ -2,6 +2,8 @@ import tests.mocks as mocks import os import pytest +from unittest.mock import AsyncMock, MagicMock +from okta.oauth import OAuth """ Testing Private Key Inputs @@ -39,3 +41,54 @@ def test_invalid_private_key_PEM_JWK(private_key): with pytest.raises(ValueError): generated_pem, generated_jwk = JWT.get_PEM_JWK(private_key) + + +@pytest.mark.asyncio +async def test_get_access_token(): + mock_request_executor = MagicMock() + mock_request_executor.create_request = AsyncMock(return_value=({"mock_request": "data"}, None)) + mock_response_details = MagicMock() + mock_response_details.content_type = "application/json" + mock_response_details.status = 200 + mock_request_executor.fire_request = AsyncMock( + return_value=(None, mock_response_details, '{"access_token": "mock_token", "expires_in": 3600}', None)) + + config = { + "client": { + "orgUrl": "https://example.okta.com", + "clientId": "valid-client-id", + "privateKey": mocks.SAMPLE_RSA, + "scopes": ["scope1", "scope2"], + "oauthTokenRenewalOffset": 5 + } + } + oauth = OAuth(mock_request_executor, config) + token, error = await oauth.get_access_token() + + assert token == "mock_token" + assert error is None + + +@pytest.mark.asyncio +async def test_clear_access_token(): + mock_request_executor = MagicMock() + mock_request_executor._cache = MagicMock() + mock_request_executor._default_headers = {} + + config = { + "client": { + "orgUrl": "https://example.okta.com", + "clientId": "valid-client-id", + "privateKey": "valid-private-key", + "scopes": ["scope1", "scope2"], + "oauthTokenRenewalOffset": 5 + } + } + oauth = OAuth(mock_request_executor, config) + oauth._access_token = "mock_token" + oauth._access_token_expiry_time = 1234567890 + + oauth.clear_access_token() + + assert oauth._access_token is None + assert oauth._access_token_expiry_time is None \ No newline at end of file