From 85614edd74db7cce69ab9fe50f382de7fa5b775f Mon Sep 17 00:00:00 2001 From: Ray Luo Date: Sat, 28 Jun 2025 12:34:56 -0700 Subject: [PATCH] Prompt parameter customizable and default to None --- docs/abc.rst | 3 +++ identity/django.py | 15 +++++++++++++-- identity/flask.py | 5 ++--- identity/pallet.py | 28 +++++++++++++++++++++++++--- identity/quart.py | 5 ++--- 5 files changed, 45 insertions(+), 11 deletions(-) diff --git a/docs/abc.rst b/docs/abc.rst index ebdedcd..c2908ff 100644 --- a/docs/abc.rst +++ b/docs/abc.rst @@ -11,4 +11,7 @@ It is an abstract base class. You cannot use it directly. .. autoclass:: identity.pallet.PalletAuth :members: + :inherited-members: + + .. automethod:: __init__ diff --git a/identity/django.py b/identity/django.py index b8ccacd..c490fc4 100644 --- a/identity/django.py +++ b/identity/django.py @@ -38,6 +38,7 @@ def __init__( self, *args, post_logout_view: Optional[callable] = None, + prompt: Optional[str] = None, **kwargs, ): """Initialize the Auth class for a Django web application. @@ -57,7 +58,18 @@ def __init__( ) where ``my_post_logout_view`` is a Django view function. + + :param str prompt: + Optional. The prompt parameter to be used during login. + Valid values are defined in + `OpenID Connect Core spec `_. + + Starting from Identity 0.11.0, + the default value is changed from ``"select_account"`` to ``None``. + ``None`` means no prompt will be sent in the authentication request, + not even string ``"none"``. The Identity Server will decide whether to prompt. """ + self._prompt = prompt super(Auth, self).__init__(*args, **kwargs) route, redirect_view = _parse_redirect_uri(self._redirect_uri) self.urlpattern = path(route, include([ @@ -90,7 +102,7 @@ def login( log_in_result = self._build_auth(request.session).log_in( scopes=scopes, # Have user consent to scopes (if any) during log-in redirect_uri=self._redirect_uri, # Optional. If present, this absolute URL must match your app's redirect_uri registered in Azure Portal - prompt="select_account", # Optional. More values defined in https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest + prompt=self._prompt, # Optional. More values defined in https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest next_link=next_link, ) if "error" in log_in_result: @@ -209,4 +221,3 @@ def wrapper(request, *args, **kwargs): scopes=scopes, ) return wrapper - diff --git a/identity/flask.py b/identity/flask.py index 1425401..848c65e 100644 --- a/identity/flask.py +++ b/identity/flask.py @@ -69,7 +69,7 @@ def build_app(): If provided, it shall be the view (which is a function) that will be redirected to, after the user has logged out. - It also passes extra parameters to :class:`identity.web.WebFrameworkAuth`. + It also passes extra parameters to :class:`identity.pallet.PalletAuth`. """ self._request = request # Not available during class definition self._session = session # Not available during class definition @@ -100,7 +100,7 @@ def login( log_in_result: dict = self._auth.log_in( scopes=scopes, # Have user consent to scopes (if any) during log-in redirect_uri=self._redirect_uri, - prompt="select_account", # Optional. More values defined in https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest + prompt=self._prompt, # self._prompt was defined in parent class next_link=next_link, ) if "error" in log_in_result: @@ -166,4 +166,3 @@ def call_an_api(*, context): ... """ return super(Auth, self).login_required(function, scopes=scopes) - diff --git a/identity/pallet.py b/identity/pallet.py index a246e01..0827bce 100644 --- a/identity/pallet.py +++ b/identity/pallet.py @@ -11,11 +11,33 @@ logger = logging.getLogger(__name__) -class PalletAuth(WebFrameworkAuth): # A common base class for Flask and Quart +class PalletAuth(WebFrameworkAuth): + """A common base class for Flask and Quart web authentication. + + Provides shared functionality for login handling, session management, and routing + used by both Flask and Quart framework implementations. + """ _endpoint_prefix = "identity" # A convention to match the template's folder name _auth: Optional[Auth] = None # None means not initialized yet - def __init__(self, app, *args, **kwargs): + def __init__(self, app, *args, prompt: Optional[str] = None, **kwargs): + """Initialize the Auth class for a Pallet-based web application. + + :param app: + The Flask or Quart application instance, or ``None``. + If None, you must call init_app() later. This pattern can be useful + when your project does not use a global app object, such as when using + the application factory pattern. + :param str prompt: + Optional. The prompt parameter to be used during login. + Valid values are defined in + `OpenID Connect Core spec `_. + + Starting from Identity 0.11.0, + the default value is changed from ``"select_account"`` to ``None``. + ``None`` means no prompt will be sent in the authentication request, + not even string ``"none"``. The Identity Server will decide whether to prompt. + """ if not ( self._Blueprint and self._Session and self._redirect and getattr(self, "_session", None) is not None @@ -24,6 +46,7 @@ def __init__(self, app, *args, **kwargs): raise RuntimeError( "Subclass must provide " "_Blueprint, _Session, _redirect, _session, and _request.") + self._prompt = prompt super(PalletAuth, self).__init__(*args, **kwargs) self._bp = bp = self._Blueprint( self._endpoint_prefix, @@ -106,4 +129,3 @@ def wrapper(*args, **kwargs): # Save an http 302 by calling self.login(request) instead of redirect(self.login) return self.login(next_link=self._request.url, scopes=scopes) return wrapper - diff --git a/identity/quart.py b/identity/quart.py index 6a554cf..7edf420 100644 --- a/identity/quart.py +++ b/identity/quart.py @@ -69,7 +69,7 @@ def build_app(): If provided, it shall be the view (which is a function) that will be redirected to, after the user has logged out. - It also passes extra parameters to :class:`identity.web.WebFrameworkAuth`. + It also passes extra parameters to :class:`identity.pallet.PalletAuth`. """ self._request = request # Not available during class definition self._session = session # Not available during class definition @@ -98,7 +98,7 @@ async def login( log_in_result = self._auth.log_in( scopes=scopes, # Have user consent to scopes (if any) during log-in redirect_uri=self._redirect_uri, - prompt="select_account", # Optional. More values defined in https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest + prompt=self._prompt, # self._prompt was defined in parent class next_link=next_link, ) if "error" in log_in_result: @@ -165,4 +165,3 @@ async def call_api(*, context): """ return super(Auth, self).login_required(function, scopes=scopes) -