Skip to content

Commit 6bd16c1

Browse files
committed
Flip USE_REGISTER_V2 to true.
This continues the registration form migration to the new RegistrationV2 and deprecating the old RegisterForm and ConfirmRegisterForm. Fix codecov.yml - they are validating it now and our ignore: line was in wrong place. Lets just allow templates - I don't think they actually get counted anyway.
1 parent 7a515d0 commit 6bd16c1

19 files changed

Lines changed: 240 additions & 110 deletions

CHANGES.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,14 @@ Fixes
1313

1414
Docs and Chores
1515
+++++++++++++++
16-
- (:pr:`xx`) Drop support for Python 3.9. This removes the dependency on importlib_resources,
16+
- (:pr:`1106`) Drop support for Python 3.9. This removes the dependency on importlib_resources,
1717
updates pypy to 3.10, and uses 3.12 as base python for tests/tox.
18+
- (:pr:`xx`) Flip :py:data:`SECURITY_USE_REGISTER_V2` default to ``True``.
19+
20+
Backwards Compatibility Concerns
21+
+++++++++++++++++++++++++++++++++
22+
As mentioned above - the default RegisterForm is now the new RegisterFormV2 - Please read :ref:`register_form_migration`.
23+
Flask-Security will emit a DeprecationWarning if the :py:data:`SECURITY_USE_REGISTER_V2` is set to False.
1824

1925
Version 5.6.2
2026
-------------

codecov.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,3 @@ coverage:
1010
if_ci_failed: error #success, failure, error, ignore
1111
informational: false
1212
only_pulls: false
13-
ignore:
14-
- "flask_security/flask_security/templates"

docs/configuration.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -958,12 +958,15 @@ Registerable
958958
959959
The :py:class:`flask_security.RegisterFormV2` is a single form used for registration. This is replacing the
960960
RegisterForm and ConfirmRegisterForm (over a few releases). Setting this option
961-
to ``True`` will set both registration forms to RegisterFormV2. Note that this
961+
to ``False`` will revert behavior to prior releases with register_form=RegisterForm and
962+
confirm_register_form=ConfirmRegisterForm. Note that this
962963
option is ignored if the application has sub-classed the registration form.
963964

964-
Default: ``False``
965+
Default: ``True``
965966

966967
.. versionadded:: 5.6.0
968+
.. versionchanged:: 5.7.0
969+
Default set to ``True``
967970

968971

969972

docs/customizing.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ replacement class. This allows you to add extra fields to any
104104
form or override validators. For example it is often desired to add additional
105105
personal information fields to the registration form::
106106

107-
from flask_security import RegisterForm
107+
from flask_security import RegisterFormV2
108108
from wtforms import StringField
109109
from wtforms.validators import DataRequired
110110

111-
class ExtendedRegisterForm(RegisterForm):
111+
class ExtendedRegisterForm(RegisterFormV2):
112112
first_name = StringField('First Name', [DataRequired()])
113113
last_name = StringField('Last Name', [DataRequired()])
114114

@@ -200,7 +200,7 @@ The following is a list of all the available form overrides:
200200
Register Form Migration
201201
++++++++++++++++++++++++
202202
Since early in Flask Security releases, there have been 2 different forms used for
203-
registration: RegisterForm and ConfirmRegisterForm. The difference between them is only
203+
registration: RegisterForm and ConfirmRegisterForm. The only difference between them is
204204
that the ConfirmRegisterForm doesn't require password confirmation (i.e. asking the user to
205205
re-type their password). This wasn't a config option but rather based on whether :py:data:`SECURITY_CONFIRMABLE` was
206206
set or whether the request was form-based or JSON. This has always been a huge source of
@@ -219,6 +219,8 @@ The new RegisterFormV2 will add a ``password_confirm`` field if :py:data:`SECURI
219219
is set to ``True`` (the default). Additionally, JSON requests will need to provide a value for ``password_confirm``
220220
if configured.
221221

222+
In release 5.7 the default is flipped - :py:data:`SECURITY_USE_REGISTER_V2` is ``True`` and RegisterFormV2 is the default form.
223+
222224
.. _form_instantiation:
223225

224226
Controlling Form Instantiation

docs/openapi.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2298,7 +2298,7 @@ components:
22982298
password_confirm:
22992299
type: string
23002300
description: >
2301-
If present, must re-type in password. This will not be present if the __SECURITY_CONFIRM__ configuration is true.
2301+
If present, must re-type in password. This will not be present if the __SECURITY_PASSWORD_CONFIRM_REQUIRED__ configuration is False.
23022302
next:
23032303
type: string
23042304
description: >

flask_security/cli.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Command Line Interface for managing accounts and roles.
66
77
:copyright: (c) 2016 by CERN.
8-
:copyright: (c) 2019-2024 by J. Christopher Wagner
8+
:copyright: (c) 2019-2025 by J. Christopher Wagner
99
:license: MIT, see LICENSE for more details.
1010
"""
1111

@@ -153,8 +153,12 @@ def users_create(attributes, password, active, username):
153153
# it already asked for confirmation.
154154
# if they used inline keywords, there really isn't any reason to make them type
155155
# it in twice.
156+
if _security.forms["confirm_register_form"].cls:
157+
form_name = "confirm_register_form"
158+
else:
159+
form_name = "register_form"
156160
form = build_form(
157-
"confirm_register_form" if _security._use_confirm_form else "register_form",
161+
form_name,
158162
meta={"csrf": False},
159163
**kwargs,
160164
password_confirm=password,

flask_security/core.py

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@
137137
"SUBDOMAIN": None,
138138
"FLASH_MESSAGES": True,
139139
"RETURN_GENERIC_RESPONSES": False,
140-
"USE_REGISTER_V2": False,
140+
"USE_REGISTER_V2": True,
141141
"I18N_DOMAIN": "flask_security",
142142
"I18N_DIRNAME": "builtin",
143143
"EMAIL_VALIDATOR_ARGS": None,
@@ -1239,6 +1239,10 @@ class Security:
12391239
.. versionadded:: 5.6.0
12401240
``username_recovery_form``, ``change_username_form``,
12411241
1242+
.. versionchanged:: 5.7.0
1243+
``register_form`` default value is RegisterFormV2 and
1244+
``confirm_register_form`` default is now ``None``.
1245+
12421246
.. deprecated:: 4.0.0
12431247
``send_mail`` and ``send_mail_task``. Replaced with ``mail_util_cls``.
12441248
``two_factor_verify_password_form`` removed.
@@ -1263,8 +1267,8 @@ def __init__(
12631267
verify_form: t.Type[VerifyForm] = VerifyForm,
12641268
change_email_form: t.Type[ChangeEmailForm] = ChangeEmailForm,
12651269
change_username_form: t.Type[ChangeUsernameForm] = ChangeUsernameForm,
1266-
confirm_register_form: t.Type[ConfirmRegisterForm] = ConfirmRegisterForm,
1267-
register_form: t.Type[RegisterForm] | t.Type[RegisterFormV2] = RegisterForm,
1270+
confirm_register_form: t.Type[ConfirmRegisterForm] | None = None,
1271+
register_form: t.Type[RegisterForm] | t.Type[RegisterFormV2] = RegisterFormV2,
12681272
forgot_password_form: t.Type[ForgotPasswordForm] = ForgotPasswordForm,
12691273
reset_password_form: t.Type[ResetPasswordForm] = ResetPasswordForm,
12701274
change_password_form: t.Type[ChangePasswordForm] = ChangePasswordForm,
@@ -1511,9 +1515,8 @@ def init_app(
15111515
):
15121516
self.forms[form_name].cls = form_cls
15131517

1514-
self._use_confirm_form = True
15151518
# deprecate confirm_register_form, ConfirmRegisterForm and RegisterForm
1516-
if self.forms["confirm_register_form"].cls != ConfirmRegisterForm:
1519+
if self.forms["confirm_register_form"].cls:
15171520
warnings.warn(
15181521
"The ConfirmRegisterForm and the confirm_register_form"
15191522
" option are"
@@ -1522,10 +1525,8 @@ def init_app(
15221525
DeprecationWarning,
15231526
stacklevel=2,
15241527
)
1525-
if (
1526-
self.forms["register_form"].cls
1527-
and self.forms["register_form"].cls != RegisterForm
1528-
and issubclass(self.forms["register_form"].cls, RegisterForm)
1528+
if self.forms["register_form"].cls and issubclass(
1529+
self.forms["register_form"].cls, RegisterForm
15291530
):
15301531
warnings.warn(
15311532
"The RegisterForm is"
@@ -1534,15 +1535,20 @@ def init_app(
15341535
DeprecationWarning,
15351536
stacklevel=2,
15361537
)
1537-
if cv("USE_REGISTER_V2", app=app):
1538+
if not cv("USE_REGISTER_V2", app=app):
1539+
warnings.warn(
1540+
"The SECURITY_USE_REGISTER_V2 configuration option is"
1541+
" deprecated as of version 5.7.0 and will be removed in a future"
1542+
" release.",
1543+
DeprecationWarning,
1544+
stacklevel=2,
1545+
)
1546+
# Switch back to old register and confirm_register forms
15381547
# Only do this is they haven't subclassed
1539-
if self.forms["register_form"].cls == RegisterForm:
1540-
self.forms["register_form"].cls = RegisterFormV2
1541-
self.forms["confirm_register_form"].cls = None
1542-
if self.forms["register_form"].cls and issubclass(
1543-
self.forms["register_form"].cls, RegisterFormV2
1544-
):
1545-
self._use_confirm_form = False
1548+
if self.forms["register_form"].cls == RegisterFormV2:
1549+
self.forms["register_form"].cls = RegisterForm
1550+
if not self.forms["confirm_register_form"].cls:
1551+
self.forms["confirm_register_form"].cls = ConfirmRegisterForm
15461552

15471553
# The following will be set as attributes and initialized from constructor or
15481554
# kwargs or config.

flask_security/forms.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,9 @@ class ConfirmRegisterForm(Form, RegisterFormMixin, UniqueEmailFormMixin):
675675
to still return important bad-password messages.
676676
In the case of an existing email or username - we set form.existing_xx so that
677677
the view can decide how to match responses (e.g. json responses always return 200).
678+
679+
.. deprecated:: 5.6.0
680+
Replaced with RegisterFormV2
678681
"""
679682

680683
# Password optional when Unified Signin enabled.
@@ -723,6 +726,12 @@ def validate(self, **kwargs: t.Any) -> bool:
723726

724727

725728
class RegisterForm(ConfirmRegisterForm, NextFormMixin):
729+
"""Register Form
730+
731+
.. deprecated:: 5.6.0
732+
Replaced with RegisterFormV2
733+
"""
734+
726735
# Password optional when Unified Signin enabled.
727736
password_confirm = PasswordField(
728737
get_form_field_label("retype_password"),

flask_security/views.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -290,11 +290,9 @@ def logout():
290290
def register() -> ResponseValue:
291291
"""View function which handles a registration request."""
292292

293-
# For some unknown historic reason - if you don't require confirmation
294-
# (via email) then you need to type in your password twice. That might
295-
# make sense if you can't reset your password but in modern (2020) UX models
296-
# don't ask twice.
297-
if (_security.confirmable or request.is_json) and _security._use_confirm_form:
293+
if (_security.confirmable or request.is_json) and _security.forms[
294+
"confirm_register_form"
295+
].cls:
298296
form_name = "confirm_register_form"
299297
else:
300298
form_name = "register_form"

pytest.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ filterwarnings =
3535
ignore::DeprecationWarning:pony:0
3636
ignore:.*'sms' was enabled in SECURITY_US_ENABLED_METHODS;.*:UserWarning:flask_security:0
3737
ignore:.*'get_token_status' is deprecated.*:DeprecationWarning:flask_security:0
38+
ignore:.*The SECURITY_USE_REGISTER_V2 configuration option is deprecated.*:DeprecationWarning:flask_security:0

0 commit comments

Comments
 (0)