Skip to content

Commit

Permalink
Add change username endpoint/view
Browse files Browse the repository at this point in the history
closes #1055
  • Loading branch information
jwag956 committed Jan 14, 2025
1 parent 1525d04 commit 930275f
Show file tree
Hide file tree
Showing 23 changed files with 753 additions and 24 deletions.
3 changes: 2 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ Features & Improvements
+++++++++++++++++++++++
- (:issue:`1038`) Add support for 'secret_key' rotation (jamesejr)
- (:issue:`980`) Add support for username recovery in simple login flows (jamesejr)
- (:issue:`1055`) Add support for changing username
- (:pr:`1048`) Add support for Python 3.13
- (:issue:`1043`) Unify Register forms (and split out re-type password option)
- (:pr:`xx`) Remove deprecated TWO_FACTOR configuration variables
- (:pr:`1052`) Remove deprecated TWO_FACTOR configuration variables

Notes
+++++
Expand Down
6 changes: 6 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ Forms

.. autoclass:: flask_security.ChangeEmailForm
.. autoclass:: flask_security.ChangePasswordForm
.. autoclass:: flask_security.ChangeUsernameForm
.. autoclass:: flask_security.ConfirmRegisterForm
.. autoclass:: flask_security.Form
.. autoclass:: flask_security.FormInfo
Expand Down Expand Up @@ -387,6 +388,11 @@ sends the following signals.

.. versionadded:: 3.3.0

.. data:: username_changed

Sent when a username is successfully changed. In addition to the
app (which is the sender), it is passed the `user` and `old_username` arguments.

.. data:: username_recovery_email_sent

Sent when a username is successfully recovered and sent over email. In addition to the
Expand Down
68 changes: 62 additions & 6 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1039,7 +1039,6 @@ Confirmable

Changeable
----------
Configuration variables for the ``SECURITY_CHANGEABLE`` feature:

.. py:data:: SECURITY_CHANGEABLE
Expand Down Expand Up @@ -1557,17 +1556,17 @@ Username-Recovery

.. py:data:: SECURITY_USERNAME_RECOVERY
Specifies whether username recovery is enabled. If set to ``True`` the UserModel
must contain a column ``"username"``. Note that this feature is independent
of the :py:data:`SECURITY_USERNAME_ENABLE` feature.
Specifies whether username recovery is enabled. If set to ``True`` the UserModel
must contain a column ``"username"``. Note that this feature is independent
of the :py:data:`SECURITY_USERNAME_ENABLE` feature.

Default: ``False``.

.. py:data:: SECURITY_USERNAME_RECOVERY_URL
Specifies the username recovery URL.
Specifies the username recovery URL.

Default: ``"/recover-username"``.
Default: ``"/recover-username"``.

.. py:data:: SECURITY_EMAIL_SUBJECT_USERNAME_RECOVERY
Expand All @@ -1581,6 +1580,59 @@ Username-Recovery

Default: ``"security/recover_username.html"``.

Change Username
-----------------

.. versionadded:: 5.6.0

.. py:data:: SECURITY_CHANGE_USERNAME
Specifies whether change username feature is enabled.
This feature should be used in conjunction with
the :py:data:`SECURITY_USERNAME_ENABLE` feature.

Default: ``False``.

.. py:data:: SECURITY_CHANGE_USERNAME_URL
Specifies the change username URL.

Default: ``"/change-username"``.

.. py:data:: SECURITY_POST_CHANGE_USERNAME_VIEW
Specifies the view to redirect to after a user successfully changes their username.
This value can be set to a URL or an endpoint name.
If this value is ``None``, the user is redirected to the
value of :data:`SECURITY_POST_LOGIN_VIEW`.

Default: ``None``.

.. py:data:: SECURITY_SEND_USERNAME_CHANGE_EMAIL
If ``True`` then an email will be sent to the registered user upon
successful change of their username.

Default: ``True``.

.. py:data:: SECURITY_EMAIL_SUBJECT_USERNAME_CHANGE_NOTICE
Sets subject for the change username email.

Default: ``_(""Your username has been changed"")``.

.. py:data:: SECURITY_CHANGE_USERNAME_TEMPLATE
Specifies the path to the template for the change username page.

Default: ``"security/change_username.html"``.

Additional relevant configuration variables:

* :py:data:`SECURITY_FRESHNESS` - Used to protect /change-username.
* :py:data:`SECURITY_FRESHNESS_GRACE_PERIOD` - Used to protect /change-username.


Passwordless
-------------

Expand Down Expand Up @@ -1893,6 +1945,7 @@ Feature Flags
All feature flags. By default all are ``False``/not enabled.

* :py:data:`SECURITY_CHANGE_EMAIL`
* :py:data:`SECURITY_CHANGE_USERNAME`
* :py:data:`SECURITY_CONFIRMABLE`
* :py:data:`SECURITY_REGISTERABLE`
* :py:data:`SECURITY_RECOVERABLE`
Expand All @@ -1916,6 +1969,7 @@ A list of all URLs and Views:
* :py:data:`SECURITY_REGISTER_URL` ``"/register"``
* :py:data:`SECURITY_CHANGE_EMAIL_URL` ``"change-email"``
* :py:data:`SECURITY_CHANGE_EMAIL_CONFIRM_URL` ``"/change-email-confirm"``
* :py:data:`SECURITY_CHANGE_USERNAME_URL` ``"change-username"``
* :py:data:`SECURITY_RESET_URL` ``"/reset"``
* :py:data:`SECURITY_CHANGE_URL` ``"/change"``
* :py:data:`SECURITY_CONFIRM_URL` ``"/confirm"``
Expand Down Expand Up @@ -1966,6 +2020,7 @@ A list of all templates:
* :py:data:`SECURITY_RESET_PASSWORD_TEMPLATE`
* :py:data:`SECURITY_CHANGE_PASSWORD_TEMPLATE`
* :py:data:`SECURITY_CHANGE_EMAIL_TEMPLATE`
* :py:data:`SECURITY_CHANGE_USERNAME_TEMPLATE`
* :py:data:`SECURITY_MULTI_FACTOR_RECOVERY_TEMPLATE`
* :py:data:`SECURITY_MULTI_FACTOR_RECOVERY_CODES_TEMPLATE`
* :py:data:`SECURITY_SEND_CONFIRMATION_TEMPLATE`
Expand Down Expand Up @@ -2059,6 +2114,7 @@ The default messages and error levels can be found in ``core.py``.
* ``SECURITY_MSG_US_SPECIFY_IDENTITY``
* ``SECURITY_MSG_USE_CODE``
* ``SECURITY_MSG_USER_DOES_NOT_EXIST``
* ``SECURITY_MSG_USERNAME_CHANGE``
* ``SECURITY_MSG_USERNAME_INVALID_LENGTH``
* ``SECURITY_MSG_USERNAME_ILLEGAL_CHARACTERS``
* ``SECURITY_MSG_USERNAME_DISALLOWED_CHARACTERS``
Expand Down
13 changes: 10 additions & 3 deletions docs/customizing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ following is a list of view templates:
* `security/reset_password.html`
* `security/change_password.html`
* `security/change_email.html`
* `security/change_username.html`
* `security/send_confirmation.html`
* `security/send_login.html`
* `security/verify.html`
Expand Down Expand Up @@ -81,6 +82,7 @@ The following is a list of all the available context processor decorators:
* ``reset_password_context_processor``: Reset password view
* ``change_password_context_processor``: Change password view
* ``change_email_context_processor``: Change email view
* ``change_username_context_processor``: Change username view
* ``send_confirmation_context_processor``: Send confirmation view
* ``send_login_context_processor``: Send login view
* ``mail_context_processor``: Whenever an email will be sent
Expand Down Expand Up @@ -168,6 +170,7 @@ The following is a list of all the available form overrides:
* ``reset_password_form``: Reset password form
* ``change_password_form``: Change password form
* ``change_email_form``: Change email form
* ``change_username_form``: Change username form (:py:class:`flask_security.ChangeUsernameForm`)
* ``send_confirmation_form``: Send confirmation form
* ``mf_recovery_codes_form``: Setup recovery codes form
* ``mf_recovery_form``: Use recovery code form
Expand Down Expand Up @@ -403,6 +406,8 @@ The following is a list of email templates:
* `security/email/change_notice.html`
* `security/email/change_email_instructions.txt`
* `security/email/change_email_instructions.html`
* `security/email/change_username_notice.txt`
* `security/email/change_username_notice.html`
* `security/email/welcome.html`
* `security/email/welcome.txt`
* `security/email/welcome_existing.html`
Expand Down Expand Up @@ -444,9 +449,9 @@ to ``False`` will bypass sending of the email (they all default to ``True``).
In most cases, in addition to an email being sent, a :ref:`Signal <signals_topic>` is sent.
The table below summarizes all this:

============================= ================================== ============================================= ====================== ===============================
============================= =================================== ============================================= ====================== ===============================
**Template Name** **Gate Config** **Subject Config** **Context Vars** **Signal Sent**
----------------------------- ---------------------------------- --------------------------------------------- ---------------------- -------------------------------
----------------------------- ----------------------------------- --------------------------------------------- ---------------------- -------------------------------
welcome SECURITY_SEND_REGISTER_EMAIL SECURITY_EMAIL_SUBJECT_REGISTER - user user_registered
- confirmation_link
- confirmation_token
Expand All @@ -465,6 +470,8 @@ reset_instructions SEND_PASSWORD_RESET_EMAIL SECURITY_EM
reset_notice SEND_PASSWORD_RESET_NOTICE_EMAIL SECURITY_EMAIL_SUBJECT_PASSWORD_NOTICE - user password_reset

change_notice SEND_PASSWORD_CHANGE_EMAIL SECURITY_EMAIL_SUBJECT_PASSWORD_CHANGE_NOTICE - user password_changed
change_username_notice SEND_USERNAME_PASSWORD_CHANGE_EMAIL SECURITY_EMAIL_SUBJECT_USERNAME_CHANGE_NOTICE - user username_changed
- old_username
two_factor_instructions N/A SECURITY_EMAIL_SUBJECT_TWO_FACTOR - user tf_security_token_sent
- token
- username
Expand All @@ -479,7 +486,7 @@ welcome_existing_username SECURITY_SEND_REGISTER_EMAIL SECURITY_EM
SECURITY_RETURN_GENERIC_RESPONSES - username
username_recovery SECURITY_USERNAME_RECOVERY SECURITY_EMAIL_SUBJECT_USERNAME_RECOVERY - user username_recovery_email_sent
- username
============================= ================================== ============================================= ====================== ===============================
============================= =================================== ============================================= ====================== ===============================

When sending an email, Flask-Security goes through the following steps:

Expand Down
3 changes: 3 additions & 0 deletions docs/features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ able to authenticate with EITHER email or username - however that can be changed
The :py:data:`SECURITY_USERNAME_RECOVERY` option adds an endpoint that allows users
to recover a forgotten username (via email).

The :py:data:`SECURITY_CHANGE_USERNAME` option adds an endpoint that can be
used by authenticated users to change their username.

Email Confirmation
------------------
If :ref:`configured<configuration:Confirmable>`, your application
Expand Down
76 changes: 75 additions & 1 deletion docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,73 @@ paths:
schema:
type: string

/change-username:
get:
summary: GET change username form
responses:
200:
description: change username form
content:
text/html:
schema:
type: string
description: render_template(SECURITY_CHANGE_USERNAME_TEMPLATE)
example: render_template(SECURITY_CHANGE_USERNAME_TEMPLATE)
application/json:
schema:
allOf:
- $ref: '#/components/schemas/DefaultJsonResponse'
- type: object
properties:
response:
type: object
properties:
current_username:
type: string
description: Current username
post:
summary: Change username
parameters:
- name: X-XSRF-Token
in: header
schema:
$ref: "#/components/headers/X-CSRF-Token"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ChangeUsername"
application/x-www-form-urlencoded:
schema:
$ref: "#/components/schemas/ChangeUsername"
responses:
200:
description: Change username response.
content:
text/html:
schema:
description: Form validation error.
type: string
example: render_template(SECURITY_CHANGE_USERNAME_TEMPLATE) with error values
application/json:
schema:
$ref: "#/components/schemas/DefaultJsonResponse"
302:
description: Username has been changed (non-json)
headers:
Location:
description: |
On success: Redirect to ``SECURITY_POST_CHANGE_USERNAME_VIEW`` or
``SECURITY_POST_LOGIN_VIEW``
schema:
type: string
400:
description: Errors while validating form
content:
application/json:
schema:
$ref: "#/components/schemas/DefaultJsonErrorResponse"
/reset:
get:
summary: GET reset password form
Expand Down Expand Up @@ -689,7 +756,7 @@ paths:
content:
application/json:
schema:
$ref: "#components/schemas/DefaultJsonErrorResponse"
$ref: "#/components/schemas/DefaultJsonErrorResponse"
/confirm:
get:
summary: GET send confirmation form
Expand Down Expand Up @@ -2266,6 +2333,13 @@ components:
email:
type: string
description: New email requested
ChangeUsername:
type: object
required: [username]
properties:
username:
type: string
description: New username

EmailLink:
type: object
Expand Down
2 changes: 2 additions & 0 deletions flask_security/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# flake8: noqa: F401
from .changeable import admin_change_password
from .change_email import ChangeEmailForm
from .change_username import ChangeUsernameForm
from .core import (
Security,
RoleMixin,
Expand Down Expand Up @@ -90,6 +91,7 @@
user_registered,
user_not_registered,
username_recovery_email_sent,
username_changed,
us_security_token_sent,
us_profile_changed,
wan_deleted,
Expand Down
Loading

0 comments on commit 930275f

Please sign in to comment.