Skip to content

Expose http_cache parameter, with its docs and recipe #407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 15, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 56 additions & 1 deletion msal/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ def __init__(
# This way, it holds the same positional param place for PCA,
# when we would eventually want to add this feature to PCA in future.
exclude_scopes=None,
http_cache=None,
):
"""Create an instance of application.

Expand Down Expand Up @@ -336,6 +337,60 @@ def __init__(
If that is unnecessary or undesirable for your app,
now you can use this parameter to supply an exclusion list of scopes,
such as ``exclude_scopes = ["offline_access"]``.

:param dict http_cache:
MSAL has long been caching tokens in the ``token_cache``.
Recently, MSAL also introduced a concept of ``http_cache``,
by automatically caching some finite amount of non-token http responses,
so that *long-lived*
``PublicClientApplication`` and ``ConfidentialClientApplication``
would be more performant and responsive in some situations.

This ``http_cache`` parameter accepts any dict-like object.
If not provided, MSAL will use an in-memory dict.

If your app is a command-line app (CLI),
you would want to persist your http_cache across different CLI runs.
The following recipe shows a way to do so::

# Just add the following lines at the beginning of your CLI script
import sys, atexit, pickle
http_cache_filename = sys.argv[0] + ".http_cache"
try:
with open(http_cache_filename, "rb") as f:
persisted_http_cache = pickle.load(f) # Take a snapshot
except (
IOError, # A non-exist http cache file
pickle.UnpicklingError, # A corrupted http cache file
EOFError, # An empty http cache file
AttributeError, ImportError, IndexError, # Other corruption
):
persisted_http_cache = {} # Recover by starting afresh
atexit.register(lambda: pickle.dump(
# When exit, flush it back to the file.
# It may occasionally overwrite another process's concurrent write,
# but that is fine. Subsequent runs will reach eventual consistency.
persisted_http_cache, open(http_cache_file, "wb")))

# And then you can implement your app as you normally would
app = msal.PublicClientApplication(
"your_client_id",
...,
http_cache=persisted_http_cache, # Utilize persisted_http_cache
...,
#token_cache=..., # You may combine the old token_cache trick
# Please refer to token_cache recipe at
# https://msal-python.readthedocs.io/en/latest/#msal.SerializableTokenCache
)
app.acquire_token_interactive(["your", "scope"], ...)

Content inside ``http_cache`` are cheap to obtain.
There is no need to share them among different apps.

Content inside ``http_cache`` will contain no tokens nor
Personally Identifiable Information (PII). Encryption is unnecessary.

New in version 1.16.0.
"""
self.client_id = client_id
self.client_credential = client_credential
Expand Down Expand Up @@ -370,7 +425,7 @@ def __init__(
self.http_client.mount("https://", a)
self.http_client = ThrottledHttpClient(
self.http_client,
{} # Hard code an in-memory cache, for now
{} if http_cache is None else http_cache, # Default to an in-memory dict
)

self.app_name = app_name
Expand Down