@@ -13,13 +13,13 @@ depending on the functionality your app requires. Aside from this, you're free
1313to add any additional fields to your model(s) if you want.
1414
1515.. note ::
16- The User, Role, and WebAuthn models MUST subclass their respective mixin (along
16+ The User, Role, WebAuthn, and RefreshTracker models MUST subclass their respective mixin (along
1717 with any other mixin the datastore requires). The pre-packaged models described
1818 below do this for you.
1919
2020 .. code-block :: python
2121
22- from flask_security import UserMixin, RoleMixin, WebAuthMixin
22+ from flask_security import UserMixin, RoleMixin, WebAuthMixin, RefreshTrackerMixin
2323
2424 class User (< db specific base > , UserMixin ):
2525 ... define columns here
@@ -45,15 +45,15 @@ using 'raw' sqlalchemy or Flask-SQLAlchemy-Lite.
4545
4646.. note::
4747 Using these models, you can override the tables names (and provide them to .set_db_info()
48- however your model class names MUST be `User` , `Role` , and `WebAuthn ` .
48+ however your model class names MUST be `User` , `Role` , `WebAuthn` , and `RefreshTracker ` .
4949
5050Flask- SQLAlchemy
5151^^^^^^^^^^^^^^^^
5252Your application code should import just the required version e.g.:
5353
5454.. code- block:: python
5555
56- from flask_security.models import fsqla_v3 as fsqla
56+ from flask_security.models import fsqla_v2 as fsqla
5757 from flask_sqlalchemy import SQLAlchemy
5858
5959 db = SQLAlchemy(app)
@@ -194,7 +194,7 @@ will require the following additional field:
194194
195195Separate Identity Domains
196196^^^^^^^^^^^^^^^^^^^^^^^^^
197- If you want authentication tokens to not be invalidated when the user changes their
197+ If you want authentication and refresh tokens to not be invalidated when the user changes their
198198password add the following to your `User` model:
199199
200200* `` fs_token_uniquifier`` (string, 64 bytes , unique, non- nullable)
@@ -308,6 +308,87 @@ the User record (since we need to look up the ``User`` based on a WebAuthn ``cre
308308 calls `` delete_instance(recursive = True )`` which correctly deals with ensuring
309309 that WebAuthn records get deleted if a User is deleted.
310310
311+ .. _refresh_tracker_model:
312+
313+ Refresh Tokens
314+ ^^^^^^^^^^^^^^
315+ Flask Security supports refresh tokens by enabling
316+ :py:data:`SECURITY_REFRESH_TOKEN ` . Internal to Flask- Security, refresh tokens
317+ are tracked using a `` refresh_tracker`` table. This requires an additional table as well as
318+ references from the User model. Users can have many refresh trackers/ tokens.
319+
320+ .. important::
321+ It is important that you maintain data consistency when deleting refresh_tracker
322+ records or users.
323+
324+ The `FsRefreshTracker` model requires the following fields:
325+
326+ * `` id `` (primary key)
327+ * `` refresh_family`` (string, 64 bytes , indexed, non- nullable, unique)
328+ * `` gen`` (integer, non- nullable)
329+ * `` expires_at`` (datetime, non- nullable)
330+ * `` revoked_at`` (datetime)
331+ * `` last_used_at`` (datetime, non- nullable)
332+ * `` name`` (string, 64 bytes , non- nullable)
333+
334+ The User record needs to have a list of refresh trackers.
335+
336+ ** For SQLAlchemy** :
337+
338+ - Add the following to the FsRefreshTracker model (assuming your primary key is named `` id `` ):
339+
340+ .. code- block:: python
341+
342+ @ declared_attr
343+ def user_id(cls ) -> Mapped[int ]:
344+ return mapped_column(
345+ ForeignKey(" user.id" , ondelete = " CASCADE" )
346+ )
347+
348+ - Add the following to the User model:
349+
350+ .. code- block:: python
351+
352+ @ declared_attr
353+ def refresh_trackers(cls ):
354+ return relationship(
355+ " FsRefreshTracker" , cascade = " all, delete"
356+ )
357+
358+ ** For mongoengine** :
359+
360+ - Add the following to the FsRefreshTracker model:
361+
362+ .. code- block:: python
363+
364+ user = ReferenceField(" User" )
365+
366+ - Add the following to the User model:
367+
368+ .. code- block:: python
369+
370+ refresh_trackers = ListField(ReferenceField(FsRefreshTracker, reverse_delete_rule = PULL ), default = [])
371+
372+ - To make sure all FsRefreshTracker objects are deleted if the User is deleted:
373+
374+ .. code- block:: python
375+
376+ User.register_delete_rule(FsRefreshTracker, " user" , CASCADE )
377+
378+ ** For peewee** :
379+
380+ Add the following to the FsRefreshTracker model:
381+
382+ .. code- block:: python
383+
384+ user = ForeignKeyField(User, backref = " refresh_trackers" )
385+
386+ This will add a column called `` user_id`` that references the User model' s
387+ `` id `` primary key field. It will also create a virtual column `` refresh_trackers``
388+ as part of the User model. Note that the default Peewee datastore implementation
389+ calls `` delete_instance(recursive = True )`` which correctly deals with ensuring
390+ that FsRefreshTracker records get deleted if a User is deleted.
391+
311392
312393Recovery Codes
313394^^^^^^^^^^^^^^^
0 commit comments