What is the correct implementation to refresh a token with MSAL in Microsoft Graph API?

Viewed 1580

I have a desktop program that requires user permissions to access a Sharepoint list. I have implemented the necessary structure to authenticate a user and retrieve its token with acquire_token_silent() method. As uploading into a list may take some time, I want to make sure the token is refreshed. I can not make the user login again because that would stop the uploading process due to the redirect to the login form. After doing some research I have implemented the next code:

Before uploading data refresh token and check:

token = _get_token_from_cache(MYSCOPE)
        if not token:
            return redirect(login page)

During the data upload:

token = _get_token_from_cache(MYSCOPE) 
if not token: 
   token = methodB(MYSCOPE)
   if not token: 
      return redirect(login page) 

The function methodB is:


def methodB(scope):
    cache = _load_cache() 
    a = _build_msal_app(cache=cache)
    accounts = cca.get_accounts()
    if accounts:  # So all account(s) belong to the current signed-in user
        result = a.acquire_token_silent(scope, account=accounts[0])
    if not result:
        result = app.acquire_token_by_xxx(scope)
        _save_cache(cache)
        return result

As in the beginning, I already check if the user is loged I would like to know if there is any way to avoid the login redirect during the uploading process. Thanks in advance.

2 Answers

If we already have some accounts that the end user already used to sign in before, acquire_token_silent will find a token in cache for this account and it will automatically handle the token refresh for you.

But if there is no suitable token in the cache, you need to send a request to AAD to obtain a token.

You could use Username Password Flow to avoid the login redirect, only this one fits your situation although it is not recommended. There is a sample using Python.

accounts = app.get_accounts(username=config["username"])
if accounts:
    logging.info("Account(s) exists in cache, probably with token too. Let's try.")
    result = app.acquire_token_silent(config["scope"], account=accounts[0])

if not result:
    logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
    result = app.acquire_token_by_username_password(
        config["username"], config["password"], scopes=config["scope"])

The configuration file would look like this:

{
    "authority": "https://login.microsoftonline.com/<your tenant id>",
    "client_id": "your_client_id",
    "username": "your_username@your_tenant.com",
    "password": "This is a sample only. You better NOT persist your password.",
    "scope": ["User.ReadBasic.All"],
    "endpoint": "https://graph.microsoft.com/v1.0/users"
}

I know this question already has a chosen answer. I would like to provide some more relevant information for your consideration.

The OP started by mentioning the app in question is a "desktop program", but the code snippet was derived from MSAL Python's web app sample. For a desktop program, you would be better of starting from MSAL's interactive sample which also takes care of refreshing your tokens.

That way, you won't need to use the username password method, which is not recommended anyway.

Related