diff --git a/identity/version.py b/identity/version.py index 0a976bb..2d758d9 100644 --- a/identity/version.py +++ b/identity/version.py @@ -1 +1 @@ -__version__ = "0.5.0" # Note: Perhaps update ReadTheDocs and README.md too? +__version__ = "0.5.1" # Note: Perhaps update ReadTheDocs and README.md too? diff --git a/identity/web.py b/identity/web.py index 2ede800..6b81942 100644 --- a/identity/web.py +++ b/identity/web.py @@ -1,6 +1,8 @@ +import functools import logging import time +import requests import msal @@ -233,6 +235,10 @@ def _get_token_for_user(self, scopes, force_refresh=None): return result return {"error": "interaction_required", "error_description": "Cache missed"} + @functools.lru_cache(maxsize=1) + def _get_oidc_config(self): + return requests.get(f"{self._authority}/.well-known/openid-configuration").json() + def log_out(self, homepage): # The vocabulary is "log out" (rather than "sign out") in the specs # https://openid.net/specs/openid-connect-frontchannel-1_0.html @@ -248,8 +254,15 @@ def log_out(self, homepage): """ self._session.pop(self._USER, None) # Must self._session.pop(self._TOKEN_CACHE, None) # Optional - return "{authority}/oauth2/v2.0/logout?post_logout_redirect_uri={hp}".format( - authority=self._authority, hp=homepage) + try: + # Empirically, Microsoft Entra ID's /v2.0 endpoint shows an account picker + # but its default (i.e. v1.0) endpoint will sign out the (only?) account + e = self._get_oidc_config().get("end_session_endpoint") + except requests.exceptions.RequestException as e: + logger.exception("Failed to get OIDC config") + return homepage + else: + return f"{e}?post_logout_redirect_uri={homepage}" if e else homepage def get_token_for_client(self, scopes): """Get access token for the current app, with specified scopes. diff --git a/setup.cfg b/setup.cfg index 826060f..085a2cb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,7 +33,7 @@ long_description_content_type = text/markdown python_requires = >=3.7 install_requires = msal>=1.16,<2 - # requests>=2.0.0,<3 + requests>=2.0.0,<3 # importlib; python_version == "2.6" # See also https://setuptools.readthedocs.io/en/latest/userguide/quickstart.html#dependency-management