@@ -170,6 +170,7 @@ def __init__(
170
170
# This way, it holds the same positional param place for PCA,
171
171
# when we would eventually want to add this feature to PCA in future.
172
172
exclude_scopes = None ,
173
+ http_cache = None ,
173
174
):
174
175
"""Create an instance of application.
175
176
@@ -336,6 +337,60 @@ def __init__(
336
337
If that is unnecessary or undesirable for your app,
337
338
now you can use this parameter to supply an exclusion list of scopes,
338
339
such as ``exclude_scopes = ["offline_access"]``.
340
+
341
+ :param dict http_cache:
342
+ MSAL has long been caching tokens in the ``token_cache``.
343
+ Recently, MSAL also introduced a concept of ``http_cache``,
344
+ by automatically caching some finite amount of non-token http responses,
345
+ so that *long-lived*
346
+ ``PublicClientApplication`` and ``ConfidentialClientApplication``
347
+ would be more performant and responsive in some situations.
348
+
349
+ This ``http_cache`` parameter accepts any dict-like object.
350
+ If not provided, MSAL will use an in-memory dict.
351
+
352
+ If your app is a command-line app (CLI),
353
+ you would want to persist your http_cache across different CLI runs.
354
+ The following recipe shows a way to do so::
355
+
356
+ # Just add the following lines at the beginning of your CLI script
357
+ import sys, atexit, pickle
358
+ http_cache_filename = sys.argv[0] + ".http_cache"
359
+ try:
360
+ with open(http_cache_filename, "rb") as f:
361
+ persisted_http_cache = pickle.load(f) # Take a snapshot
362
+ except (
363
+ IOError, # A non-exist http cache file
364
+ pickle.UnpicklingError, # A corrupted http cache file
365
+ EOFError, # An empty http cache file
366
+ AttributeError, ImportError, IndexError, # Other corruption
367
+ ):
368
+ persisted_http_cache = {} # Recover by starting afresh
369
+ atexit.register(lambda: pickle.dump(
370
+ # When exit, flush it back to the file.
371
+ # It may occasionally overwrite another process's concurrent write,
372
+ # but that is fine. Subsequent runs will reach eventual consistency.
373
+ persisted_http_cache, open(http_cache_file, "wb")))
374
+
375
+ # And then you can implement your app as you normally would
376
+ app = msal.PublicClientApplication(
377
+ "your_client_id",
378
+ ...,
379
+ http_cache=persisted_http_cache, # Utilize persisted_http_cache
380
+ ...,
381
+ #token_cache=..., # You may combine the old token_cache trick
382
+ # Please refer to token_cache recipe at
383
+ # https://msal-python.readthedocs.io/en/latest/#msal.SerializableTokenCache
384
+ )
385
+ app.acquire_token_interactive(["your", "scope"], ...)
386
+
387
+ Content inside ``http_cache`` are cheap to obtain.
388
+ There is no need to share them among different apps.
389
+
390
+ Content inside ``http_cache`` will contain no tokens nor
391
+ Personally Identifiable Information (PII). Encryption is unnecessary.
392
+
393
+ New in version 1.16.0.
339
394
"""
340
395
self .client_id = client_id
341
396
self .client_credential = client_credential
@@ -370,7 +425,7 @@ def __init__(
370
425
self .http_client .mount ("https://" , a )
371
426
self .http_client = ThrottledHttpClient (
372
427
self .http_client ,
373
- {} # Hard code an in-memory cache, for now
428
+ {} if http_cache is None else http_cache , # Default to an in-memory dict
374
429
)
375
430
376
431
self .app_name = app_name
0 commit comments