Azure-Samples / ms-identity-python-webapp

A Python web application calling Microsoft graph that is secured using the Microsoft identity platform
MIT License
298 stars 143 forks source link

Flask (identity.web): How to silently refresh User id token w/o explicit login #121

Closed victorho-ty closed 11 months ago

victorho-ty commented 1 year ago

We have a Flask App that allows user to login via url from "identity.web.Auth.log_in()". Upon explicit log-in using the link, a fresh id_token is created, with a default expiration = 1 hour, for the purpose of other API user identification.

After token expiration, the "identity.web.Auth.get_token_for_user()", would return: {'error': 'interaction_required', 'error_description': 'Log in required'}

What is the way to allow logged-in users to silently refresh its token (as this app web session is active w/o logout)? As otherwise, the user would have to re-click the "identity.web.Auth.log_in()" link every hour.

Appreciate on to do so silently w/o user interaction. Thanks

rayluo commented 1 year ago

At one point, the older versions of this sample kept user session for longer than one hour, but later we chose to honor the ID token expiry. But you also made a good point, perhaps we could silently refresh the ID token. Marking this as an enhancement request. Please subscribe (i.e., click the Watch button at the upper right of this repo's home page) the future update of this sample.

@rayluo Saw your comment on that the demo app does NOT take care of token refresh

Meanwhile, @victorho-ty , would you also tell me where I commented that line? I want to double check. Thanks. :)

victorho-ty commented 1 year ago

@rayluo Sorry for the confusion. I misread. You actually said it DOES take care of token refresh (below). May I please ask more details on how/where does this demo app take care of the silent token refresh?

We are referencing this as the backbone of the Auth, but the behavior we see is "identity.web.Auth.get_token_for_user()" would return error after token's 1 hr expiration.

https://github.com/Azure-Samples/ms-identity-python-webapp/issues/46 "If you were referring to how this web app uses a short-lived access token to access another web api, this web app sample (and its underlying MSAL library) does take care of the token refresh, under the hood. Basically, we just use the web app's session as a token storage."

rayluo commented 1 year ago

Thanks for clarifying that statement from #46. We are good here. :-)

how/where does this demo app take care of the silent token refresh?

You do not see it from this demo app, because it is designed as an underlying behavior that was implemented inside the get_token_for_user(). It is just that the current one-hour sign-in expiration behavior overrides the token refresh behavior. We will revisit that implementation in the near future.

victorho-ty commented 1 year ago

Hi @rayluo, thanks for the comment. For our version adapted from the demo, we are not limiting web-sign-in for 1 hour, but we are still getting the get_token_for_user() returning error after token expiration. Would you know of possible reasons? could it be do with token caching enabling/disabling, and the location of the token cache?

Note: Our server.config['SESSION_TYPE'] = 'filesystem' is already filesystem for Flask.

rayluo commented 1 year ago

For our version adapted from the demo, we are not limiting web-sign-in for 1 hour, but we are still getting the get_token_for_user() returning error after token expiration. Would you know of possible reasons?

It is on us. You will receive notification on this issue and/or release after we make some changes.

victorho-ty commented 1 year ago

Like to get a better understanding as it's a blocker: 1) Is this an issue in "identity.web (0.3.0)"? as it seems not in the demo layer. 2) Any workaround (e.g. with token cache store) that can work with "identity.web (0.3.0)"? 3) token refresh happens automatically fine in MSAL PublicClientApplication.acquire_token_silent() for desktop. Any idea if we can adapt that for the web Flask usecase?

Thanks

victorho-ty commented 1 year ago

I seem to see where the issue/bug is in identity.web.

def _get_user(self):
    id_token_claims = self._session.get(self._USER)
    return id_token_claims if id_token_claims is not None and _is_valid(
        id_token_claims) else None

In get_user(), it tries to validate the 'exp' of the session saved user. Even though the user has refreshed access/id token when accessing other protected API (i.e. token with exp to a later time than login time), this Flask session saved user id_claim still retains the exp (as of log_in time only), and hence this error will happen 1 hour after complete_login()

Is there a better place to raise this issue/bug?

rayluo commented 1 year ago

Is there a better place to raise this issue/bug?

Sure. You can create an issue here.

victorho-ty commented 1 year ago

Thanks for looking.

loopasam commented 1 year ago

we have a similar issue with our internal app (invalid token needing refresh after 1h), just to make sure I understand correctly: This is not something that can be configured from the Azure admin interface, it should be done with identity?

rayluo commented 1 year ago

@loopasam and @victorho-ty , correct. Try manually upgrading to identity 0.3.1+ and see how that goes.

loopasam commented 11 months ago

sorry, late reply. It looks like identity 0.3.2 indeed fixed the 1h limit, thanks.