Repository: snowflakedb/snowflake-connector-python

Issue:
SNOW-721779: Client MFA caching not working in 2.9.0
Please answer these questions before submitting your issue. Thanks!

1. What version of Python are you using?

```
Python 3.9.16 (main, Dec 21 2022, 09:20:09) 
[GCC 8.3.0]
```
2. What operating system and processor architecture are you using?

```
Linux-5.15.49-linuxkit-x86_64-with-glibc2.28
```
3. What are the component versions in the environment (`pip freeze`)?
```
aiohttp==3.8.3
aiohttp-cors==0.7.0
aiosignal==1.3.1
alembic==1.8.1
anyio==3.6.2
argo-workflows==6.3.5
argon2-cffi==21.3.0
argon2-cffi-bindings==21.2.0
asn1crypto==1.5.1
asttokens==2.1.0
async-timeout==4.0.2
attrs==22.1.0
Babel==2.11.0
backcall==0.2.0
beautifulsoup4==4.11.1
BentoML==0.13.2
black==22.10.0
bleach==5.0.1
boto3==1.26.18
botocore==1.29.18
build==0.9.0
cachetools==5.2.0
Cerberus==1.3.4
certifi==2022.9.24
cffi==1.15.1
cfgv==3.3.1
chardet==5.0.0
charset-normalizer==2.1.1
click==8.1.3
cloudpickle==2.2.0
colorlog==6.7.0
configparser==5.3.0
contextlib2==21.6.0
contourpy==1.0.6
cramjam==2.6.2
cryptography==38.0.4
cycler==0.11.0
databricks-cli==0.17.3
debugpy==1.6.4
decorator==5.1.1
deepmerge==1.1.0
defusedxml==0.7.1
distlib==0.3.6
docker==6.0.1
entrypoints==0.4
eradicate==2.1.0
exceptiongroup==1.0.4
executing==1.2.0
fastjsonschema==2.16.2
fastparquet==2022.11.0
filelock==3.8.0
flake8==5.0.4
flake8-black==0.3.5
flake8-broken-line==0.6.0
flake8-bugbear==22.10.27
flake8-builtins==2.0.1
flake8-comprehensions==3.10.1
flake8-docstrings==1.6.0
flake8-eradicate==1.4.0
flake8-import-order==0.18.2
flake8-mutable==1.2.0
flake8-plugin-utils==1.3.2
flake8-pytest-style==1.6.0
flake8-SQL==0.4.1
flake8-tidy-imports==4.8.0
flake8-use-fstring==1.4
Flask==2.2.2
fonttools==4.38.0
frozenlist==1.3.3
fsspec==2022.11.0
gcsfs==0.7.2
gitdb==4.0.10
GitPython==3.1.29
google-api-core==2.10.2
google-api-python-client==2.66.0
google-auth==2.14.1
google-auth-httplib2==0.1.0
google-auth-oauthlib==0.7.1
google-cloud-core==2.3.2
google-cloud-storage==2.6.0
google-crc32c==1.5.0
google-resumable-media==2.4.0
googleapis-common-protos==1.57.0
greenlet==2.0.1
grpcio==1.50.0
grpcio-status==1.48.2
gunicorn==20.1.0
hera-workflows==4.2.0
httplib2==0.21.0
humanfriendly==10.0
identify==2.5.9
idna==3.4
importlib-metadata==5.1.0
iniconfig==1.1.1
ipykernel==6.17.1
ipython==8.7.0
ipython-genutils==0.2.0
ipywidgets==8.0.2
isort==5.10.1
itsdangerous==2.1.2
jaraco.classes==3.2.3
jedi==0.18.2
jeepney==0.8.0
Jinja2==3.1.2
jmespath==1.0.1
joblib==1.2.0
jplephem==2.18
json5==0.9.10
jsonschema==4.17.1
jupyter-server==1.23.3
jupyter_client==7.4.7
jupyter_core==5.1.0
jupyterlab==3.5.0
jupyterlab-pygments==0.2.2
jupyterlab-widgets==3.0.3
jupyterlab_server==2.16.3
keyring==23.11.0
kiwisolver==1.4.4
lightgbm==3.3.3
lunardate==0.2.0
Mako==1.2.4
MarkupSafe==2.1.1
matplotlib==3.6.2
matplotlib-inline==0.1.6
mccabe==0.7.0
mistune==2.0.4
mlflow-skinny==1.27.0
more-itertools==9.0.0
multidict==6.0.2
mypy==0.991
mypy-extensions==0.4.3
nbclassic==0.4.8
nbclient==0.7.0
nbconvert==7.2.5
nbformat==5.7.0
nbstripout==0.6.1
nest-asyncio==1.5.6
nodeenv==1.7.0
notebook==6.5.2
notebook_shim==0.2.2
numpy==1.23.5
oauthlib==3.2.2
oscrypto==1.3.0
packaging==21.3
pandas==1.5.2
pandas-vet==0.2.3
pandocfilters==1.5.0
parso==0.8.3
pathspec==0.10.2
patito==0.4.3
pep517==0.13.0
pep8-naming==0.13.2
pexpect==4.8.0
pickleshare==0.7.5
Pillow==9.3.0
pip-tools==6.10.0
platformdirs==2.5.4
plotly==5.11.0
pluggy==1.0.0
polars==0.15.1
pre-commit==2.20.0
prometheus-client==0.15.0
prompt-toolkit==3.0.33
protobuf==3.20.3
psutil==5.9.4
psycopg2-binary==2.9.5
ptyprocess==0.7.0
pure-eval==0.2.2
pyarrow==8.0.0
pyasn1==0.4.8
pyasn1-modules==0.2.8
pyCalverter==1.6.1
pycodestyle==2.9.1
pycparser==2.21
pycryptodomex==3.16.0
pydantic==1.10.2
pydocstyle==6.1.1
pyflakes==2.5.0
Pygments==2.13.0
PyJWT==2.6.0
pyluach==2.0.2
pyOpenSSL==22.0.0
pyparsing==3.0.9
pyrsistent==0.19.2
pytest==7.2.0
pytest-flake8==1.1.1
pytest-mypy==0.10.2
python-dateutil==2.8.2
python-dotenv==0.21.0
python-json-logger==2.0.4
pytz==2022.6
PyYAML==6.0
pyzmq==24.0.1
requests==2.28.1
requests-oauthlib==1.3.1
rsa==4.9
ruamel.yaml==0.17.21
ruamel.yaml.clib==0.2.7
s3transfer==0.6.0
schema==0.7.5
scikit-learn==1.1.3
scipy==1.9.3
SecretStorage==3.3.3
Send2Trash==1.8.0
sgp4==2.21
simple-di==0.1.0
six==1.16.0
skyfield==1.45
skyfield-data==4.0.0
smmap==5.0.0
sniffio==1.3.0
snowballstemmer==2.2.0
snowflake-connector-python==2.9.0
snowflake-sqlalchemy==1.4.4
soupsieve==2.3.2.post1
SQLAlchemy==1.4.44
SQLAlchemy-Utils==0.38.3
sqlparse==0.4.3
stack-data==0.6.2
tabulate==0.9.0
tenacity==8.1.0
terminado==0.17.0
threadpoolctl==3.1.0
tinycss2==1.2.1
toml==0.10.2
tomli==2.0.1
tornado==6.2
traitlets==5.5.0
typing_extensions==4.4.0
uritemplate==4.1.1
urllib3==1.26.13
virtualenv==20.17.0
wcwidth==0.2.5
webencodings==0.5.1
websocket-client==1.4.2
Werkzeug==2.2.2
widgetsnbextension==4.0.3
workalendar==15.0.1
xgboost==1.7.1
yarl==1.8.1
zipp==3.11.0
```
4. What did you do?

```
import os
import logging
import snowflake.connector

db_params = {
    'user' : os.getenv("SNOWFLAKE_USER"),
    'account' : os.getenv("SNOWFLAKE_ACCOUNT"),
    'role': os.getenv("SNOWFLAKE_ROLE"),
    'warehouse': os.getenv("SNOWFLAKE_WAREHOUSE"),
    'authenticator' : os.getenv("SNOWFLAKE_AUTHENTICATOR"),
    'password': os.getenv("SNOWFLAKE_PASSWORD"),
    'database' : os.getenv("SNOWFLAKE_DATABASE"),
    'schema' : os.getenv("SNOWFLAKE_SCHEMA"),
     'client_request_mfa_token' :  True,
    'client_store_temporary_credential' : True}

def run_query():
  with snowflake.connector.connect(**db_params) as con:
      cur = con.cursor()
      result = cur.execute('select 1 from dual;')
      df = result.fetch_pandas_all()
  return df

run_query() #  Received MFA push duo notifications
run_query() #  Received MFA push duo notifications
```


5. What did you expect to see?
The second invocation of run_query() should use the temporary stored credentials
```
run_query() #  Received MFA push duo notifications
run_query() #  Use temporary client credentials
```

6. Can you set logging to DEBUG and collect the logs?

 ```
2023-01-05 14:13:08,360 - MainThread connection.py:280 - __init__() - INFO - Snowflake Connector for Python Version: 2.9.0, Python Version: 3.9.16, Platform: Linux-5.15.49-linuxkit-x86_64-with-glibc2.28
2023-01-05 14:13:08,362 - MainThread connection.py:536 - connect() - DEBUG - connect
2023-01-05 14:13:08,363 - MainThread connection.py:832 - __config() - DEBUG - __config
2023-01-05 14:13:08,364 - MainThread connection.py:965 - __config() - INFO - This connection is in OCSP Fail Open Mode. TLS Certificates would be checked for validity and revocation status. Any other Certificate Revocation related exceptions or OCSP Responder failures would be disregarded in favor of connectivity.
2023-01-05 14:13:08,366 - MainThread converter.py:145 - __init__() - DEBUG - use_numpy: False
2023-01-05 14:13:08,367 - MainThread connection.py:729 - __open_connection() - DEBUG - REST API object was created: ***ACCOUNT***.snowflakecomputing.com:443
2023-01-05 14:13:08,369 - MainThread _auth.py:171 - authenticate() - DEBUG - authenticate
2023-01-05 14:13:08,370 - MainThread _auth.py:201 - authenticate() - DEBUG - assertion content: *********
2023-01-05 14:13:08,371 - MainThread _auth.py:204 - authenticate() - DEBUG - account=mv21709, user=***USERNAME***, database=***DATABASE_NAME***, schema=***SCHEMA_NAME***, warehouse=***WAREHOUSE***, role=***ROLE***, request_id=70c33502-ff3a-4950-8ebd-e4e2b564361d
2023-01-05 14:13:08,371 - MainThread _auth.py:237 - authenticate() - DEBUG - body['data']: {'CLIENT_APP_ID': 'PythonConnector', 'CLIENT_APP_VERSION': '2.9.0', 'SVN_REVISION': None, 'ACCOUNT_NAME': 'mv21709', 'LOGIN_NAME': '***USERNAME***', 'CLIENT_ENVIRONMENT': {'APPLICATION': 'PythonConnector', 'OS': 'Linux', 'OS_VERSION': 'Linux-5.15.49-linuxkit-x86_64-with-glibc2.28', 'PYTHON_VERSION': '3.9.16', 'PYTHON_RUNTIME': 'CPython', 'PYTHON_COMPILER': 'GCC 8.3.0', 'OCSP_MODE': 'FAIL_OPEN', 'TRACING': 10, 'LOGIN_TIMEOUT': 120, 'NETWORK_TIMEOUT': None}, 'SESSION_PARAMETERS': {'CLIENT_PREFETCH_THREADS': 4, 'CLIENT_REQUEST_MFA_TOKEN': True}}
2023-01-05 14:13:08,373 - MainThread _auth.py:247 - authenticate() - DEBUG - Timeout set to 120
2023-01-05 14:13:08,374 - MainThread retry.py:351 - from_int() - DEBUG - Converted retries value: 1 -> Retry(total=1, connect=None, read=None, redirect=None, status=None)
2023-01-05 14:13:08,376 - MainThread retry.py:351 - from_int() - DEBUG - Converted retries value: 1 -> Retry(total=1, connect=None, read=None, redirect=None, status=None)
2023-01-05 14:13:08,377 - MainThread network.py:1155 - _use_requests_session() - DEBUG - Session status for SessionPool '***ACCOUNT***.snowflakecomputing.com', SessionPool 1/1 active sessions
2023-01-05 14:13:08,378 - MainThread network.py:835 - _request_exec_wrapper() - DEBUG - remaining request timeout: 120, retry cnt: 1
2023-01-05 14:13:08,380 - MainThread network.py:816 - add_request_guid() - DEBUG - Request guid: 1fcdae93-0c23-499c-b375-4dbfbfde1098
2023-01-05 14:13:08,380 - MainThread network.py:1014 - _request_exec() - DEBUG - socket timeout: 60
2023-01-05 14:13:08,383 - MainThread connectionpool.py:1003 - _new_conn() - DEBUG - Starting new HTTPS connection (1): ***ACCOUNT***.snowflakecomputing.com:443
2023-01-05 14:13:08,536 - MainThread ssl_wrap_socket.py:80 - ssl_wrap_socket_with_ocsp() - DEBUG - OCSP Mode: FAIL_OPEN, OCSP response cache file name: None
2023-01-05 14:13:08,538 - MainThread ocsp_snowflake.py:523 - reset_ocsp_response_cache_uri() - DEBUG - ocsp_response_cache_uri: file:///root/.cache/snowflake/ocsp_response_cache.json
2023-01-05 14:13:08,539 - MainThread ocsp_snowflake.py:526 - reset_ocsp_response_cache_uri() - DEBUG - OCSP_VALIDATION_CACHE size: 195
2023-01-05 14:13:08,540 - MainThread ocsp_snowflake.py:333 - reset_ocsp_dynamic_cache_server_url() - DEBUG - OCSP response cache server is enabled: http://ocsp.snowflakecomputing.com/ocsp_response_cache.json
2023-01-05 14:13:08,541 - MainThread ocsp_snowflake.py:346 - reset_ocsp_dynamic_cache_server_url() - DEBUG - OCSP dynamic cache server RETRY URL: None
2023-01-05 14:13:08,542 - MainThread ocsp_snowflake.py:956 - validate() - DEBUG - validating certificate: ***ACCOUNT***.snowflakecomputing.com
2023-01-05 14:13:08,544 - MainThread ocsp_asn1crypto.py:427 - extract_certificate_chain() - DEBUG - # of certificates: 2
2023-01-05 14:13:08,548 - MainThread ocsp_asn1crypto.py:432 - extract_certificate_chain() - DEBUG - subject: OrderedDict([('country_name', 'US'), ('state_or_province_name', 'California'), ('locality_name', 'San Mateo'), ('organization_name', 'Snowflake Inc.'), ('common_name', '*.***ACCOUNT***.snowflakecomputing.com')]), issuer: OrderedDict([('country_name', 'US'), ('organization_name', 'DigiCert Inc'), ('common_name', 'DigiCert TLS RSA SHA256 2020 CA1')])
2023-01-05 14:13:08,550 - MainThread ocsp_asn1crypto.py:432 - extract_certificate_chain() - DEBUG - subject: OrderedDict([('country_name', 'US'), ('organization_name', 'DigiCert Inc'), ('common_name', 'DigiCert TLS RSA SHA256 2020 CA1')]), issuer: OrderedDict([('country_name', 'US'), ('organization_name', 'DigiCert Inc'), ('organizational_unit_name', 'www.digicert.com'), ('common_name', 'DigiCert Global Root CA')])
2023-01-05 14:13:08,559 - MainThread ocsp_asn1crypto.py:453 - create_pair_issuer_subject() - DEBUG - not found issuer_der: OrderedDict([('country_name', 'US'), ('organization_name', 'DigiCert Inc'), ('organizational_unit_name', 'www.digicert.com'), ('common_name', 'DigiCert Global Root CA')])
2023-01-05 14:13:08,562 - MainThread ocsp_snowflake.py:722 - find_cache() - DEBUG - hit cache for subject: OrderedDict([('country_name', 'US'), ('state_or_province_name', 'California'), ('locality_name', 'San Mateo'), ('organization_name', 'Snowflake Inc.'), ('common_name', '*.***ACCOUNT***.snowflakecomputing.com')])
2023-01-05 14:13:08,566 - MainThread ocsp_snowflake.py:722 - find_cache() - DEBUG - hit cache for subject: OrderedDict([('country_name', 'US'), ('organization_name', 'DigiCert Inc'), ('common_name', 'DigiCert TLS RSA SHA256 2020 CA1')])
2023-01-05 14:13:08,570 - MainThread ocsp_snowflake.py:1013 - _validate() - DEBUG - ok
2023-01-05 14:13:23,794 - MainThread connectionpool.py:456 - _make_request() - DEBUG -***ACCOUNT***:443 "POST /session/v1/login-request?request_id=70c33502-ff3a-4950-8ebd-e4e2b564361d&databaseName=***DATABASE_NAME***&schemaName=***DATABASE_NAME***&warehouse=***WAREHOUSE***&roleName=***ROLE***&request_guid=1fcdae93-0c23-499c-b375-4dbfbfde1098 HTTP/1.1" 200 None
2023-01-05 14:13:23,795 - MainThread network.py:1040 - _request_exec() - DEBUG - SUCCESS
2023-01-05 14:13:23,795 - MainThread network.py:1160 - _use_requests_session() - DEBUG - Session status for SessionPool '***ACCOUNT***.snowflakecomputing.com', SessionPool 0/1 active sessions
2023-01-05 14:13:23,796 - MainThread network.py:715 - _post_request() - DEBUG - ret[code] = None, after post request
2023-01-05 14:13:23,796 - MainThread _auth.py:366 - authenticate() - DEBUG - completed authentication
2023-01-05 14:13:23,797 - MainThread _auth.py:413 - authenticate() - DEBUG - token = ******
2023-01-05 14:13:23,797 - MainThread _auth.py:416 - authenticate() - DEBUG - master_token = ******
2023-01-05 14:13:23,798 - MainThread _auth.py:420 - authenticate() - DEBUG - id_token = NULL
2023-01-05 14:13:23,798 - MainThread _auth.py:424 - authenticate() - DEBUG - mfa_token = ******
2023-01-05 14:13:23,802 - MainThread connection.py:648 - cursor() - DEBUG - cursor
2023-01-05 14:13:23,803 - MainThread cursor.py:662 - execute() - DEBUG - executing SQL/command
2023-01-05 14:13:23,804 - MainThread cursor.py:582 - _preprocess_pyformat_query() - DEBUG - binding: [select 1 from dual;] with input=[None], processed=[{}]
2023-01-05 14:13:23,805 - MainThread cursor.py:727 - execute() - INFO - query: [select 1 from dual;]
2023-01-05 14:13:23,806 - MainThread connection.py:1334 - _next_sequence_counter() - DEBUG - sequence counter: 1
2023-01-05 14:13:23,809 - MainThread cursor.py:457 - _execute_helper() - DEBUG - Request id: 2ef7e25f-4025-42c5-b6a2-de09e8def044
2023-01-05 14:13:23,810 - MainThread cursor.py:459 - _execute_helper() - DEBUG - running query [select 1 from dual;]
2023-01-05 14:13:23,811 - MainThread cursor.py:466 - _execute_helper() - DEBUG - is_file_transfer: True
2023-01-05 14:13:23,812 - MainThread connection.py:1011 - cmd_query() - DEBUG - _cmd_query
2023-01-05 14:13:23,813 - MainThread connection.py:1034 - cmd_query() - DEBUG - sql=[select 1 from dual;], sequence_id=[1], is_file_transfer=[False]
2023-01-05 14:13:23,815 - MainThread network.py:1155 - _use_requests_session() - DEBUG - Session status for SessionPool '***ACCOUNT***.snowflakecomputing.com', SessionPool 1/1 active sessions
2023-01-05 14:13:23,816 - MainThread network.py:835 - _request_exec_wrapper() - DEBUG - remaining request timeout: None, retry cnt: 1
2023-01-05 14:13:23,816 - MainThread network.py:816 - add_request_guid() - DEBUG - Request guid: 2d621f04-9731-410a-a221-066eca492766
2023-01-05 14:13:23,820 - MainThread network.py:1014 - _request_exec() - DEBUG - socket timeout: 60
2023-01-05 14:13:23,996 - MainThread connectionpool.py:456 - _make_request() - DEBUG -***ACCOUNT***:443 "POST /queries/v1/query-request?requestId=2ef7e25f-4025-42c5-b6a2-de09e8def044&request_guid=2d621f04-9731-410a-a221-066eca492766 HTTP/1.1" 200 None
2023-01-05 14:13:23,998 - MainThread network.py:1040 - _request_exec() - DEBUG - SUCCESS
2023-01-05 14:13:23,999 - MainThread network.py:1160 - _use_requests_session() - DEBUG - Session status for SessionPool '***ACCOUNT***.snowflakecomputing.com', SessionPool 0/1 active sessions
2023-01-05 14:13:24,001 - MainThread network.py:715 - _post_request() - DEBUG - ret[code] = None, after post request
2023-01-05 14:13:24,002 - MainThread network.py:739 - _post_request() - DEBUG - Query id: 01a97295-0101-a07d-0000-024d38dd079e
2023-01-05 14:13:24,003 - MainThread cursor.py:734 - execute() - DEBUG - sfqid: 01a97295-0101-a07d-0000-024d38dd079e
2023-01-05 14:13:24,004 - MainThread cursor.py:740 - execute() - INFO - query execution done
2023-01-05 14:13:24,006 - MainThread cursor.py:754 - execute() - DEBUG - SUCCESS
2023-01-05 14:13:24,007 - MainThread cursor.py:773 - execute() - DEBUG - PUT OR GET: False
2023-01-05 14:13:24,009 - MainThread cursor.py:864 - _init_result_and_meta() - DEBUG - Query result format: arrow
2023-01-05 14:13:24,013 - MainThread cursor.py:878 - _init_result_and_meta() - INFO - Number of results in first chunk: 1
2023-01-05 14:13:24,016 - MainThread arrow_iterator.cpython-39-x86_64-linux-gnu.so:0 - __cinit__() - DEBUG - Batches read: 1
2023-01-05 14:13:24,017 - MainThread CArrowIterator.cpp:16 - CArrowIterator() - DEBUG - Arrow BatchSize: 1
2023-01-05 14:13:24,021 - MainThread result_set.py:58 - result_set_iterator() - DEBUG - beginning to schedule result batch downloads
2023-01-05 14:13:24,023 - MainThread connection.py:581 - close() - INFO - closed
2023-01-05 14:13:24,025 - MainThread telemetry.py:211 - close() - DEBUG - Closing telemetry client.
2023-01-05 14:13:24,029 - MainThread telemetry.py:176 - send_batch() - DEBUG - Sending 1 logs to telemetry. Data is {'logs': [{'message': {'driver_type': 'PythonConnector', 'driver_version': '2.9.0', 'source': 'PythonConnector', 'type': 'client_imported_packages', 'value': "{'gzip', 'OpenSSL', 'pyarrow', 'ipykernel', 'zmq', 'http', 'decorator', 'unicodedata', 'marshal', 'enum', 'codecs', 'queue', 'asyncio', 'operator', 'prompt_toolkit', 'requests', 'concurrent', 'bz2', 'pydevd', 'cryptography', 'keyword', 'pydevd_file_utils', 'genericpath', 'random', 'itertools', 'keyring', 'numpy', 'colorsys', 'faulthandler', 'mmap', 'site', 'grp', 'importlib_metadata', 'fcntl', 'typing_extensions', 'ntpath', 'ctypes', 'pyexpat', 'sqlite3', 'mpl_toolkits', 'charset_normalizer', 'termios', 'Cryptodome', 'copyreg', 'curses', 'ipaddress', 'certifi', 'entrypoints', 'jwt', 'atexit', 'pkgutil', 'parso', 'tokenize', 'struct', 'uuid', 'glob', 'time', 'xmlrpc', 'opcode', 'copy', 'weakref', 'getopt', 'cloudpickle', 'io', 'contextvars', 'select', 'logging', 'jupyter_core', 'snowflake', 'builtins', 'os', 'sre_constants', 'jedi', 'difflib', 'decimal', 'cProfile', 'google', 'bisect', 'pexpect', 'ast', 'stringprep', 'six', 'getpass', 'platformdirs', 'tarfile', 'pickleshare', 'collections', 'types', 'pandas', 'csv', 'argparse', 'lzma', 'zipimport', 'oscrypto', 'stat', 'threading', 'linecache', 'string', 'configparser', 'functools', 'dateutil', 'json', 'warnings', 'email', 'pickle', 'hashlib', 'locale', 'zipp', 'plistlib', 'uu', 'base64', 'signal', 'runpy', 'ssl', 'datetime', 'asttokens', 'psutil', 'cmath', 'resource', 'mimetypes', 'traceback', 'pydev_ipython', 'typing', 'pprint', 'urllib', 'stack_data', 'posixpath', 'html', 'cmd', 'pydoc_data', 'timeit', 'cffi', 'IPython', 'sre_compile', 'tempfile', 'sre_parse', 'secrets', 'gc', 'filecmp', 'zoneinfo', 'dis', 'zlib', 'wcwidth', 'textwrap', 'errno', 'contextlib', 'ptyprocess', 'sys', 'code', 'ruamel', 'platform', 'math', 'fnmatch', 'webbrowser', 'xml', 'zipfile', 'pkg_resources', 'asn1crypto', 'hmac', 'pydoc', 'jaraco', 'socketserver', 'cython_runtime', 'packaging', 'gettext', 're', 'pydevd_plugins', 'idna', 'tty', 'backcall', 'calendar', 'reprlib', 'urllib3', 'pdb', 'importlib', 'profile', 'subprocess', 'binascii', 'pstats', 'bdb', 'pathlib', 'pytz', 'numbers', 'pwd', 'quopri', 'abc', 'fractions', 'pycparser', 'pydevconsole', 'posix', 'token', 'shutil', 'traitlets', 'pty', 'inspect', 'selectors', 'tornado', 'debugpy', 'filelock', 'shlex', 'executing', 'socket', 'chardet', 'pydevd_tracing', 'jupyter_client', 'pure_eval', 'pygments', 'codeop', 'dataclasses', 'heapq', 'sysconfig', 'encodings', 'array'}"}, 'timestamp': '1672928003802'}, {'message': {'driver_type': 'PythonConnector', 'driver_version': '2.9.0', 'source': 'PythonConnector', 'type': 'client_time_consume_first_result', 'query_id': '01a97295-0101-a07d-0000-024d38dd079e', 'value': -65}, 'timestamp': '1672928004006'}, {'message': {'driver_type': 'PythonConnector', 'driver_version': '2.9.0', 'source': 'PythonConnector', 'type': 'client_fetch_pandas_all', 'query_id': '01a97295-0101-a07d-0000-024d38dd079e', 'value': 1}, 'timestamp': '1672928004015'}, {'message': {'driver_type': 'PythonConnector', 'driver_version': '2.9.0', 'source': 'PythonConnector', 'type': 'client_time_consume_last_result', 'query_id': '01a97295-0101-a07d-0000-024d38dd079e', 'value': 17}, 'timestamp': '1672928004023'}]}.
2023-01-05 14:13:24,030 - MainThread network.py:1155 - _use_requests_session() - DEBUG - Session status for SessionPool '***ACCOUNT***.snowflakecomputing.com', SessionPool 1/1 active sessions
2023-01-05 14:13:24,031 - MainThread network.py:835 - _request_exec_wrapper() - DEBUG - remaining request timeout: 5, retry cnt: 1
2023-01-05 14:13:24,032 - MainThread network.py:816 - add_request_guid() - DEBUG - Request guid: 39678a9f-42cb-4b90-8faa-febc7fc9598f
2023-01-05 14:13:24,033 - MainThread network.py:1014 - _request_exec() - DEBUG - socket timeout: 60
2023-01-05 14:13:24,176 - MainThread connectionpool.py:456 - _make_request() - DEBUG -***ACCOUNT***:443 "POST /telemetry/send?request_guid=39678a9f-42cb-4b90-8faa-febc7fc9598f HTTP/1.1" 200 86
2023-01-05 14:13:24,178 - MainThread network.py:1040 - _request_exec() - DEBUG - SUCCESS
2023-01-05 14:13:24,179 - MainThread network.py:1160 - _use_requests_session() - DEBUG - Session status for SessionPool '***ACCOUNT***.snowflakecomputing.com', SessionPool 0/1 active sessions
2023-01-05 14:13:24,180 - MainThread network.py:715 - _post_request() - DEBUG - ret[code] = None, after post request
2023-01-05 14:13:24,181 - MainThread telemetry.py:200 - send_batch() - DEBUG - Successfully uploading metrics to telemetry.
2023-01-05 14:13:24,184 - MainThread connection.py:584 - close() - INFO - No async queries seem to be running, deleting session
2023-01-05 14:13:24,184 - MainThread network.py:1155 - _use_requests_session() - DEBUG - Session status for SessionPool '***ACCOUNT***.snowflakecomputing.com', SessionPool 1/1 active sessions
2023-01-05 14:13:24,185 - MainThread network.py:835 - _request_exec_wrapper() - DEBUG - remaining request timeout: 5, retry cnt: 1
2023-01-05 14:13:24,186 - MainThread network.py:816 - add_request_guid() - DEBUG - Request guid: 2bd26ca6-e4ef-4ce9-9e36-37a6ccad72ad
2023-01-05 14:13:24,187 - MainThread network.py:1014 - _request_exec() - DEBUG - socket timeout: 60
2023-01-05 14:13:24,379 - MainThread connectionpool.py:456 - _make_request() - DEBUG -***ACCOUNT***:443 "POST /session?delete=true&request_guid=2bd26ca6-e4ef-4ce9-9e36-37a6ccad72ad HTTP/1.1" 200 76
2023-01-05 14:13:24,380 - MainThread network.py:1040 - _request_exec() - DEBUG - SUCCESS
2023-01-05 14:13:24,381 - MainThread network.py:1160 - _use_requests_session() - DEBUG - Session status for SessionPool '***ACCOUNT***.snowflakecomputing.com', SessionPool 0/1 active sessions
2023-01-05 14:13:24,381 - MainThread network.py:715 - _post_request() - DEBUG - ret[code] = None, after post request
2023-01-05 14:13:24,385 - MainThread connection.py:595 - close() - DEBUG - Session is closed
```
  
  --------
  - The above works fine with `2.8.3` 
  - I've attempted to clear the cache, to no success
  


<!--
If you need urgent assistance reach out to support for escalated issue processing https://community.snowflake.com/s/article/How-To-Submit-a-Support-Case-in-Snowflake-Lodge
-->


Discussion:
codecov-commenter: # [Codecov](https://codecov.io/gh/snowflakedb/snowflake-connector-python/pull/1391?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Snowflake+Computing) Report
> Merging [#1391](https://codecov.io/gh/snowflakedb/snowflake-connector-python/pull/1391?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Snowflake+Computing) (22ffa3d) into [main](https://codecov.io/gh/snowflakedb/snowflake-connector-python/commit/bee5dff58ad88a6bdb58f9cf2f4f6dde8152b1bd?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Snowflake+Computing) (bee5dff) will **decrease** coverage by `0.76%`.
> The diff coverage is `0.00%`.

```diff
@@            Coverage Diff             @@
##             main    #1391      +/-   ##
==========================================
- Coverage   81.30%   80.54%   -0.77%     
==========================================
  Files          61       61              
  Lines        8555     8557       +2     
  Branches     1262     1263       +1     
==========================================
- Hits         6956     6892      -64     
- Misses       1281     1342      +61     
- Partials      318      323       +5     
```


| [Impacted Files](https://codecov.io/gh/snowflakedb/snowflake-connector-python/pull/1391?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Snowflake+Computing) | Coverage Δ | |
|---|---|---|
| [src/snowflake/connector/connection.py](https://codecov.io/gh/snowflakedb/snowflake-connector-python/pull/1391?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Snowflake+Computing#diff-c3JjL3Nub3dmbGFrZS9jb25uZWN0b3IvY29ubmVjdGlvbi5weQ==) | `88.17% <0.00%> (-0.27%)` | :arrow_down: |
| [src/snowflake/connector/network.py](https://codecov.io/gh/snowflakedb/snowflake-connector-python/pull/1391?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Snowflake+Computing#diff-c3JjL3Nub3dmbGFrZS9jb25uZWN0b3IvbmV0d29yay5weQ==) | `78.03% <ø> (ø)` | |
| [src/snowflake/connector/azure\_storage\_client.py](https://codecov.io/gh/snowflakedb/snowflake-connector-python/pull/1391?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Snowflake+Computing#diff-c3JjL3Nub3dmbGFrZS9jb25uZWN0b3IvYXp1cmVfc3RvcmFnZV9jbGllbnQucHk=) | `47.72% <0.00%> (-43.94%)` | :arrow_down: |
| [src/snowflake/connector/ssl\_wrap\_socket.py](https://codecov.io/gh/snowflakedb/snowflake-connector-python/pull/1391?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Snowflake+Computing#diff-c3JjL3Nub3dmbGFrZS9jb25uZWN0b3Ivc3NsX3dyYXBfc29ja2V0LnB5) | `71.64% <0.00%> (-5.98%)` | :arrow_down: |
| [src/snowflake/connector/ocsp\_snowflake.py](https://codecov.io/gh/snowflakedb/snowflake-connector-python/pull/1391?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Snowflake+Computing#diff-c3JjL3Nub3dmbGFrZS9jb25uZWN0b3Ivb2NzcF9zbm93Zmxha2UucHk=) | `77.32% <0.00%> (-0.27%)` | :arrow_down: |

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Snowflake+Computing)

sfc-gh-mkeller: > Are we able to add automated testing?

We could add a new account and user to GitHub Actions, but automating the MFA retrieval would probably be too costly/difficult.

Patch:
diff --git a/src/snowflake/connector/auth/_auth.py b/src/snowflake/connector/auth/_auth.py
index ba6aba6a..d4fb3c25 100644
--- a/src/snowflake/connector/auth/_auth.py
+++ b/src/snowflake/connector/auth/_auth.py
@@ -450,7 +450,7 @@ class Auth:
             self._rest._connection._update_parameters(session_parameters)
             return session_parameters
 
-    def _read_temporary_credential(self, host, user, cred_type):
+    def _read_temporary_credential(self, host, user, cred_type) -> str | None:
         cred = None
         if IS_MACOS or IS_WINDOWS:
             if not installed_keyring:
diff --git a/src/snowflake/connector/connection.py b/src/snowflake/connector/connection.py
index ddf7610f..7fc3d2a6 100644
--- a/src/snowflake/connector/connection.py
+++ b/src/snowflake/connector/connection.py
@@ -808,10 +808,19 @@ class SnowflakeConnection:
         elif self._authenticator == OAUTH_AUTHENTICATOR:
             self.auth_class = AuthByOAuth(oauth_token=self._token)
         elif self._authenticator == USR_PWD_MFA_AUTHENTICATOR:
-            self.auth_class = AuthByUsrPwdMfa(password=self._password)
             self._session_parameters[PARAMETER_CLIENT_REQUEST_MFA_TOKEN] = (
                 self._client_request_mfa_token if IS_LINUX else True
             )
+            if self._session_parameters[PARAMETER_CLIENT_REQUEST_MFA_TOKEN]:
+                auth.read_temporary_credentials(
+                    self.host,
+                    self.user,
+                    self._session_parameters,
+                )
+            self.auth_class = AuthByUsrPwdMfa(
+                password=self._password,
+                mfa_token=self.rest.mfa_token,
+            )
         else:
             # okta URL, e.g., https://<account>.okta.com/
             self.auth_class = AuthByOkta(application=self.application)
diff --git a/src/snowflake/connector/network.py b/src/snowflake/connector/network.py
index 91b77818..e61e7d85 100644
--- a/src/snowflake/connector/network.py
+++ b/src/snowflake/connector/network.py
@@ -403,11 +403,11 @@ class SnowflakeRestful:
         self._id_token = value
 
     @property
-    def mfa_token(self):
+    def mfa_token(self) -> str | None:
         return getattr(self, "_mfa_token", None)
 
     @mfa_token.setter
-    def mfa_token(self, value):
+    def mfa_token(self, value: str) -> None:
         self._mfa_token = value
 
     def close(self):


Test patch:
diff --git a/test/unit/test_auth_mfa.py b/test/unit/test_auth_mfa.py
new file mode 100644
index 00000000..7efb9edf
--- /dev/null
+++ b/test/unit/test_auth_mfa.py
@@ -0,0 +1,51 @@
+#
+# Copyright (c) 2012-2021 Snowflake Computing Inc. All rights reserved.
+#
+
+from unittest import mock
+
+from snowflake.connector import connect
+
+
+def test_mfa_token_cache():
+    with mock.patch(
+        "snowflake.connector.network.SnowflakeRestful.fetch",
+    ):
+        with mock.patch(
+            "snowflake.connector.auth._auth.Auth._write_temporary_credential",
+        ) as save_mock:
+            with connect(
+                account="account",
+                user="user",
+                password="password",
+                authenticator="username_password_mfa",
+                client_store_temporary_credential=True,
+                client_request_mfa_token=True,
+            ):
+                assert save_mock.called
+    with mock.patch(
+        "snowflake.connector.network.SnowflakeRestful.fetch",
+        return_value={
+            "data": {
+                "token": "abcd",
+                "masterToken": "defg",
+            },
+            "success": True,
+        },
+    ):
+        with mock.patch(
+            "snowflake.connector.cursor.SnowflakeCursor._init_result_and_meta",
+        ):
+            with mock.patch(
+                "snowflake.connector.auth._auth.Auth._read_temporary_credential",
+                return_value=None,
+            ) as load_mock:
+                with connect(
+                    account="account",
+                    user="user",
+                    password="password",
+                    authenticator="username_password_mfa",
+                    client_store_temporary_credential=True,
+                    client_request_mfa_token=True,
+                ):
+                    assert load_mock.called