Utilizing Django Cache for Office 365's Token Backend
Microsoft's O365 python library offers developers a quick an easy tool for interacting with Graph APIs. I won't get into details here, but I highly recommend that you check out the documentation for its capabilities. In this post, I will be covering the library's ability to utilize a custom token cache backend and how you can hook it into Django's cache.
Before getting started, ensure that the Django cache framework is set up. In my project, I decided to use Memcached with the following configuration:
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
"LOCATION": "{0}:{1}".format(env('CACHE_HOST'), env('CACHE_PORT')),
}
}
Now we can create our custom token backend. The first step is to set up a sublcass that inherits from BaseTokenBackend
:
from O365.utils import BaseTokenBackend
class DjangoCacheTokenBackend(BaseTokenBackend):
def __init__(self):
super().__init__()
Now to actually utilize the cache, two methods must be implemented:
load_token
: Loads the token from the backend and will either return a Token instance or Nonesave_token
: Stores the token in the backend
I also recommend implementing the following optional methods:
delete_token
: Deletes the token from the backendcheck_token
: Returns a boolean representing the presence of the token in the backend
With the Django cache framework setup, the default cache can be imported and used within the class. A default key token_key
is set up in the constructor and it will be used with all interactions. The following code contains the entire Django cache token backend:
from django.core.cache import cache
from O365.utils import BaseTokenBackend
class DjangoCacheTokenBackend(BaseTokenBackend):
def __init__(self):
super().__init__()
self.token_key = 'token'
def load_token(self):
token = cache.get(self.token_key)
if token:
token = self.token_constructor(self.serializer.loads(token))
return token
def save_token(self):
if self.token is None:
raise ValueError('You have to set the "token" first.')
cache.set(self.token_key, self.serializer.dumps(self.token), 3600)
return True
def delete_token(self):
cache.delete(self.token_key)
return True
def check_token(self):
return cache.get(self.token_key) is not None
When setting up the account with o365, simply import the class, initiatlize it and pass it as the token_backend parameter:
from .token import DjangoCacheTokenBackend
credentials = (env('O365_CLIENT'), env('O365_SECRET'))
token_backend = DjangoCacheTokenBackend()
account = Account(credentials,
auth_flow_type='credentials',
tenant_id=env('O365_TENANT'),
token_backend=token_backend,
)