diff --git a/docs/configuration/authentication/cookie.md b/docs/configuration/authentication/cookie.md
index 7f0ef4d8..12b77cf2 100644
--- a/docs/configuration/authentication/cookie.md
+++ b/docs/configuration/authentication/cookie.md
@@ -9,11 +9,7 @@ from fastapi_users.authentication import CookieAuthentication
SECRET = "SECRET"
-auth_backends = []
-
cookie_authentication = CookieAuthentication(secret=SECRET, lifetime_seconds=3600)
-
-auth_backends.append(cookie_authentication)
```
As you can see, instantiation is quite simple. It accepts the following arguments:
@@ -58,7 +54,3 @@ This method will remove the authentication cookie:
## Authentication
This method expects that you provide a valid cookie in the headers.
-
-## Next steps
-
-We will now configure the main **FastAPI Users** object that will expose the [routers](../routers/index.md).
diff --git a/docs/configuration/authentication/jwt.md b/docs/configuration/authentication/jwt.md
index fdc7a035..037b4376 100644
--- a/docs/configuration/authentication/jwt.md
+++ b/docs/configuration/authentication/jwt.md
@@ -9,11 +9,7 @@ from fastapi_users.authentication import JWTAuthentication
SECRET = "SECRET"
-auth_backends = []
-
jwt_authentication = JWTAuthentication(secret=SECRET, lifetime_seconds=3600, tokenUrl="auth/jwt/login")
-
-auth_backends.append(jwt_authentication)
```
As you can see, instantiation is quite simple. It accepts the following arguments:
@@ -69,7 +65,3 @@ from fastapi import Depends, Response
async def refresh_jwt(response: Response, user=Depends(fastapi_users.current_user(active=True))):
return await jwt_authentication.get_login_response(user, response)
```
-
-## Next steps
-
-We will now configure the main **FastAPI Users** object that will expose the [routers](../routers/index.md).
diff --git a/docs/configuration/databases/mongodb.md b/docs/configuration/databases/mongodb.md
index 16cddd67..4271867a 100644
--- a/docs/configuration/databases/mongodb.md
+++ b/docs/configuration/databases/mongodb.md
@@ -6,7 +6,7 @@
Let's create a MongoDB connection and instantiate a collection.
-```py hl_lines="23 24 25 26"
+```py hl_lines="6 7 8 9 10 11"
{!./src/db_mongodb.py!}
```
@@ -17,20 +17,16 @@ You can choose any name for the database and the collection.
## Create the database adapter
-The database adapter of **FastAPI Users** makes the link between your database configuration and the users logic. Create it like this.
+The database adapter of **FastAPI Users** makes the link between your database configuration and the users logic. It should be generated by a FastAPI dependency.
-```py hl_lines="34"
+```py hl_lines="14 15"
{!./src/db_mongodb.py!}
```
-Notice that we pass a reference to your [`UserDB` model](../model.md).
+Notice that we pass a reference to your [`UserDB` model](../models.md).
!!! info
The database adapter will automatically create a [unique index](https://docs.mongodb.com/manual/core/index-unique/) on `id` and `email`.
!!! warning
- **FastAPI Users** will use its defined [`id` UUID](../model.md) as unique identifier for the user, rather than the builtin MongoDB `_id`.
-
-## Next steps
-
-We will now configure an [authentication method](../authentication/index.md).
+ **FastAPI Users** will use its defined [`id` UUID](../models.md) as unique identifier for the user, rather than the builtin MongoDB `_id`.
diff --git a/docs/configuration/databases/ormar.md b/docs/configuration/databases/ormar.md
index a9d9fc48..533a6026 100644
--- a/docs/configuration/databases/ormar.md
+++ b/docs/configuration/databases/ormar.md
@@ -24,7 +24,7 @@ For the sake of this tutorial from now on, we'll use a simple SQLite databse.
Let's declare our User ORM model.
-```py hl_lines="29-33"
+```py hl_lines="11-15"
{!./src/db_ormar.py!}
```
@@ -35,19 +35,15 @@ there to fit to your needs!
## Create the database adapter
The database adapter of **FastAPI Users** makes the link between your
-database configuration and the users logic. Create it like this.
+database configuration and the users logic. It should be generated by a FastAPI dependency.
-```py hl_lines="40"
+```py hl_lines="22-23"
{!./src/db_ormar.py!}
```
-Notice that we pass a reference to your [`UserDB` model](../model.md).
+Notice that we pass a reference to your [`UserDB` model](../models.md).
!!! warning
In production, it's strongly recommended to setup a migration system to
update your SQL schemas. See
[Alembic](https://alembic.sqlalchemy.org/en/latest/).
-
-## Next steps
-
-We will now configure an [authentication method](../authentication/index.md).
diff --git a/docs/configuration/databases/sqlalchemy.md b/docs/configuration/databases/sqlalchemy.md
index 1807ae65..0db24925 100644
--- a/docs/configuration/databases/sqlalchemy.md
+++ b/docs/configuration/databases/sqlalchemy.md
@@ -22,42 +22,38 @@ For the sake of this tutorial from now on, we'll use a simple SQLite databse.
## Setup User table
-Let's create a `metadata` object and declare our User table.
+Let's declare our SQLAlchemy `User` table.
-```py hl_lines="5 32 33"
+```py hl_lines="13 14"
{!./src/db_sqlalchemy.py!}
```
-As you can see, **FastAPI Users** provides a mixin that will include base fields for our User table. You can of course add you own fields there to fit to your needs!
+As you can see, **FastAPI Users** provides a mixin that will include base fields for our `User` table. You can of course add you own fields there to fit to your needs!
## Create the tables
We'll now create an SQLAlchemy engine and ask it to create all the defined tables.
-```py hl_lines="36 37 38 39 40"
+```py hl_lines="17 18 19 20"
{!./src/db_sqlalchemy.py!}
```
!!! warning
In production, it's strongly recommended to setup a migration system to update your SQL schemas. See [Alembic](https://alembic.sqlalchemy.org/en/latest/).
-## Create the database adapter
+## Create the database adapter dependency
-The database adapter of **FastAPI Users** makes the link between your database configuration and the users logic. Create it like this.
+The database adapter of **FastAPI Users** makes the link between your database configuration and the users logic. It should be generated by a FastAPI dependency.
-```py hl_lines="42 43"
+```py hl_lines="25 26"
{!./src/db_sqlalchemy.py!}
```
Notice that we pass it three things:
-* A reference to your [`UserDB` model](../model.md).
-* The `users` variable, which is the actual SQLAlchemy table behind the table class.
+* A reference to your [`UserDB` model](../models.md).
* A `database` instance, which allows us to do asynchronous request to the database.
-
-## Next steps
-
-We will now configure an [authentication method](../authentication/index.md).
+* The `users` variable, which is the actual SQLAlchemy table behind the table class.
## What about SQLAlchemy ORM?
diff --git a/docs/configuration/databases/tortoise.md b/docs/configuration/databases/tortoise.md
index 0c33f2bf..02542f1c 100644
--- a/docs/configuration/databases/tortoise.md
+++ b/docs/configuration/databases/tortoise.md
@@ -20,35 +20,33 @@ pip install aiosqlite
For the sake of this tutorial from now on, we'll use a simple SQLite databse.
-## Setup User table
+## Setup User table and model
Let's declare our User ORM model.
-```py hl_lines="8 9"
-{!./src/db_tortoise.py!}
+```py hl_lines="18 19"
+{!./src/db_tortoise_model.py!}
```
As you can see, **FastAPI Users** provides an abstract model that will include base fields for our User table. You can of course add you own fields there to fit to your needs!
-## Tweak `UserDB` model
-
In order to make the Pydantic model and the Tortoise ORM model working well together, you'll have to add a mixin and some configuration options to your `UserDB` model. Tortoise ORM provides [utilities to ease the integration with Pydantic](https://tortoise-orm.readthedocs.io/en/latest/contrib/pydantic.html) and we'll use them here.
-```py hl_lines="5 24 25 26 27"
-{!./src/db_tortoise.py!}
+```py hl_lines="22 23 24 25 26"
+{!./src/db_tortoise_model.py!}
```
The `PydanticModel` mixin adds methods used internally by Tortoise ORM to the Pydantic model so that it can easily transform it back to an ORM model. It expects then that you provide the property `orig_model` which should point to the **User ORM model we defined just above**.
## Create the database adapter
-The database adapter of **FastAPI Users** makes the link between your database configuration and the users logic. Create it like this.
+The database adapter of **FastAPI Users** makes the link between your database configuration and the users logic. It should be generated by a FastAPI dependency.
-```py hl_lines="32"
-{!./src/db_tortoise.py!}
+```py hl_lines="8 9"
+{!./src/db_tortoise_adapter.py!}
```
-Notice that we pass a reference to your [`UserDB` model](../model.md).
+Notice that we pass a reference to your [`UserDB` model](../models.md).
## Register Tortoise
@@ -56,13 +54,16 @@ For using Tortoise ORM we must register our models and database.
Tortoise ORM supports integration with FastAPI out-of-the-box. It will automatically bind startup and shutdown events.
-```py hl_lines="35 36 37 38 39 40"
-{!./src/db_tortoise.py!}
+```py
+from tortoise.contrib.fastapi import register_tortoise
+
+register_tortoise(
+ app,
+ db_url=DATABASE_URL,
+ modules={"models": ["models"]},
+ generate_schemas=True,
+)
```
!!! warning
In production, it's strongly recommended to setup a migration system to update your SQL schemas. See [https://tortoise-orm.readthedocs.io/en/latest/migration.html](https://tortoise-orm.readthedocs.io/en/latest/migration.html).
-
-## Next steps
-
-We will now configure an [authentication method](../authentication/index.md).
diff --git a/docs/configuration/full-example.md b/docs/configuration/full-example.md
index 288e887a..333e9e70 100644
--- a/docs/configuration/full-example.md
+++ b/docs/configuration/full-example.md
@@ -8,27 +8,20 @@ Here is a full working example with JWT authentication to help get you started.
## SQLAlchemy
-```py
-{!./src/full_sqlalchemy.py!}
-```
+
+
## MongoDB
-```py
-{!./src/full_mongodb.py!}
-```
+
## Tortoise ORM
-```py
-{!./src/full_tortoise.py!}
-```
+
## Ormar
-```py
-{!./src/full_ormar.py!}
-```
+
## What now?
diff --git a/docs/configuration/model.md b/docs/configuration/models.md
similarity index 88%
rename from docs/configuration/model.md
rename to docs/configuration/models.md
index 10aa9962..9cfdea6c 100644
--- a/docs/configuration/model.md
+++ b/docs/configuration/models.md
@@ -1,4 +1,4 @@
-# User model
+# Models
**FastAPI Users** defines a minimal User model for authentication purposes. It is structured like this:
@@ -67,15 +67,3 @@ class UserUpdate(models.BaseUserUpdate):
class UserDB(User, models.BaseUserDB):
pass
```
-
-## Next steps
-
-Depending on your database backend, the database configuration will differ a bit.
-
-[I'm using SQLAlchemy](databases/sqlalchemy.md)
-
-[I'm using MongoDB](databases/mongodb.md)
-
-[I'm using Tortoise ORM](databases/tortoise.md)
-
-[I'm using ormar](databases/ormar.md)
diff --git a/docs/configuration/oauth.md b/docs/configuration/oauth.md
index 6ac7a7e1..5a2f64ce 100644
--- a/docs/configuration/oauth.md
+++ b/docs/configuration/oauth.md
@@ -46,7 +46,7 @@ class UserCreate(models.BaseUserCreate):
pass
-class UserUpdate(User, models.BaseUserUpdate):
+class UserUpdate(models.BaseUserUpdate):
pass
diff --git a/docs/configuration/overview.md b/docs/configuration/overview.md
new file mode 100644
index 00000000..3c174347
--- /dev/null
+++ b/docs/configuration/overview.md
@@ -0,0 +1,92 @@
+# Overview
+
+The schema below shows you how the library is structured and how each part fit together.
+
+
+```mermaid
+flowchart TB
+ FASTAPI_USERS{FastAPIUsers}
+ USER_MANAGER{UserManager}
+ USER_MANAGER_DEPENDENCY[[get_user_manager]]
+ CURRENT_USER[[current_user]]
+ subgraph MODELS[Models]
+ direction RL
+ USER[User]
+ USER_CREATE[UserCreate]
+ USER_UPDATE[UserUpdate]
+ USER_DB[UserDB]
+ end
+ subgraph DATABASE[Database adapters]
+ direction RL
+ SQLALCHEMY[SQLAlchemy]
+ MONGODB[MongoDB]
+ TORTOISE[Tortoise ORM]
+ ORMAR[Ormar]
+ end
+ subgraph ROUTERS[Routers]
+ direction RL
+ REGISTER[[get_register_router]]
+ VERIFY[[get_verify_router]]
+ RESET[[get_reset_password_router]]
+ AUTH[[get_auth_router]]
+ OAUTH[[get_oauth_router]]
+ USERS[[get_users_router]]
+ end
+ subgraph AUTH_BACKENDS[Authentication backends]
+ direction RL
+ COOKIE[CookieAuthentication]
+ JWT[JWTAuthentication]
+ end
+ DATABASE --> USER_MANAGER
+
+ MODELS --> USER_MANAGER
+ MODELS --> FASTAPI_USERS
+
+ USER_MANAGER --> USER_MANAGER_DEPENDENCY
+ USER_MANAGER_DEPENDENCY --> FASTAPI_USERS
+
+ FASTAPI_USERS --> ROUTERS
+
+ AUTH_BACKENDS --> AUTH
+ AUTH_BACKENDS --> FASTAPI_USERS
+
+ FASTAPI_USERS --> CURRENT_USER
+```
+
+## Models
+
+Pydantic models representing the data structure of a user. Base classes are provided with the required fields to make authentication work. You should sub-class each of them and add your own fields there.
+
+➡️ [Configure the models](./models.md)
+
+## Database adapters
+
+FastAPI Users is compatible with various databases and ORM. To build the interface between those database tools and the library, we provide database adapters classes that you need to instantiate and configure.
+
+➡️ [I'm using SQLAlchemy](databases/sqlalchemy.md)
+
+➡️ [I'm using MongoDB](databases/mongodb.md)
+
+➡️ [I'm using Tortoise ORM](databases/tortoise.md)
+
+➡️ [I'm using ormar](databases/ormar.md)
+
+## Authentication backends
+
+Authentication backends define the way users sessions are managed in your app, like access tokens or cookies.
+
+➡️ [Configure the authentication backends](./authentication/index.md)
+
+## `UserManager`
+
+The `UserManager` object bears most of the logic of FastAPI Users: registration, verification, password reset... We provide a `BaseUserManager` with this common logic; which you should overload to define how to validate passwords or handle events.
+
+This `UserManager` object should be provided through a FastAPI dependency, `get_user_manager`.
+
+➡️ [Configure `UserManager`](./user-manager.md)
+
+## `FastAPIUsers` and routers
+
+Finally, `FastAPIUsers` object is the main class from which you'll be able to generate routers for classic routes like registration or login, but also get the `current_user` dependency factory to inject the authenticated user in your own routes.
+
+➡️ [Configure `FastAPIUsers` and routers](./routers/index.md)
diff --git a/docs/configuration/password-validation.md b/docs/configuration/password-validation.md
deleted file mode 100644
index b93d49d2..00000000
--- a/docs/configuration/password-validation.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# Password validation
-
-FastAPI Users **doesn't have any password validation logic by default**. However, there is an argument on the `FastAPIUsers` class so that you can provide your own password validation function.
-
-It'll be applied on each routes that need to validate the input password:
-
-* At registration ([`/register`](../usage/routes.md#post-register))
-* At password reset ([`/reset-password`](../usage/routes.md#post-reset-password))
-* At profile update ([`/me`](../usage/routes.md#patch-me) and [`/{user_id}`](../usage/routes.md#patch-user_id))
-
-## Configuration
-
-The FastAPIUsers class accepts an optional keyword argument `validate_password`. It expects an async function which accepts in argument:
-
-* `password` (`str`): the password to validate.
-* `user` (`Union[UserRegister, User]`): user model which we are currently validating the password. Useful if you want to check that the password doesn't contain the name or the birthdate of the user for example.
-
-This function should return `None` if the password is valid or raise `InvalidPasswordException` if not. This exception expects an argument `reason` telling why the password is invalid. It'll be part of the error response.
-
-## Example
-
-```py
-from fastapi_users import FastAPIUsers, InvalidPasswordException
-
-
-async def validate_password(
- password: str,
- user: Union[UserCreate, User],
-) -> None:
- if len(password) < 8:
- raise InvalidPasswordException(
- reason="Password should be at least 8 characters"
- )
- if user.email in password:
- raise InvalidPasswordException(
- reason="Password should not contain e-mail"
- )
-
-
-fastapi_users = FastAPIUsers(
- user_db,
- [jwt_authentication],
- User,
- UserCreate,
- UserUpdate,
- UserDB,
- validate_password=validate_password
-)
-```
diff --git a/docs/configuration/routers/auth.md b/docs/configuration/routers/auth.md
index 9fb7dc04..98294b72 100644
--- a/docs/configuration/routers/auth.md
+++ b/docs/configuration/routers/auth.md
@@ -16,7 +16,7 @@ SECRET = "SECRET"
jwt_authentication = JWTAuthentication(secret=SECRET, lifetime_seconds=3600)
fastapi_users = FastAPIUsers(
- user_db,
+ get_user_manager,
[jwt_authentication],
User,
UserCreate,
diff --git a/docs/configuration/routers/index.md b/docs/configuration/routers/index.md
index 9942bc8e..f854f1d1 100644
--- a/docs/configuration/routers/index.md
+++ b/docs/configuration/routers/index.md
@@ -1,12 +1,13 @@
# Routers
-We're almost there! The last step is to configure the `FastAPIUsers` object that will wire the database adapter, the authentication classes and let us generate the actual **API routes**.
+We're almost there! The last step is to configure the `FastAPIUsers` object that will wire the user manager, the authentication classes and let us generate the actual **API routes**.
## Configure `FastAPIUsers`
Configure `FastAPIUsers` object with all the elements we defined before. More precisely:
-* `db`: Database adapter instance.
+* `get_user_manager`: Dependency callable getter to inject the
+ user manager class instance. See [UserManager](../user-manager.md).
* `auth_backends`: List of authentication backends. See [Authentication](../authentication/index.md).
* `user_model`: Pydantic model of a user.
* `user_create_model`: Pydantic model for creating a user.
@@ -17,8 +18,8 @@ Configure `FastAPIUsers` object with all the elements we defined before. More pr
from fastapi_users import FastAPIUsers
fastapi_users = FastAPIUsers(
- user_db,
- auth_backends,
+ get_user_manager,
+ [jwt_authentication],
User,
UserCreate,
UserUpdate,
diff --git a/docs/configuration/routers/register.md b/docs/configuration/routers/register.md
index c9b360bf..2a46a9b5 100644
--- a/docs/configuration/routers/register.md
+++ b/docs/configuration/routers/register.md
@@ -16,7 +16,7 @@ SECRET = "SECRET"
jwt_authentication = JWTAuthentication(secret=SECRET, lifetime_seconds=3600)
fastapi_users = FastAPIUsers(
- user_db,
+ get_user_manager,
[jwt_authentication],
User,
UserCreate,
@@ -31,24 +31,3 @@ app.include_router(
tags=["auth"],
)
```
-
-## After register
-
-You can provide a custom function to be called after a successful registration. It is called with **two arguments**: the **user** that has just registered, and the original **`Request` object**.
-
-Typically, you'll want to **send a welcome e-mail** or add it to your marketing analytics pipeline.
-
-You can define it as an `async` or standard method.
-
-Example:
-
-```py
-def on_after_register(user: UserDB, request: Request):
- print(f"User {user.id} has registered.")
-
-app.include_router(
- fastapi_users.get_register_router(on_after_register),
- prefix="/auth",
- tags=["auth"],
-)
-```
diff --git a/docs/configuration/routers/reset.md b/docs/configuration/routers/reset.md
index 1c4df5c7..32541e3f 100644
--- a/docs/configuration/routers/reset.md
+++ b/docs/configuration/routers/reset.md
@@ -10,9 +10,13 @@ Check the [routes usage](../../usage/routes.md) to learn how to use them.
from fastapi import FastAPI
from fastapi_users import FastAPIUsers
+SECRET = "SECRET"
+
+jwt_authentication = JWTAuthentication(secret=SECRET, lifetime_seconds=3600)
+
fastapi_users = FastAPIUsers(
- user_db,
- auth_backends,
+ get_user_manager,
+ [jwt_authentication],
User,
UserCreate,
UserUpdate,
@@ -21,62 +25,7 @@ fastapi_users = FastAPIUsers(
app = FastAPI()
app.include_router(
- fastapi_users.get_reset_password_router("SECRET"),
- prefix="/auth",
- tags=["auth"],
-)
-```
-
-Parameters:
-
-* `reset_password_token_secret` (`Union[str, pydantic.SecretStr]`): Secret to encode reset password token.
-* `reset_password_token_lifetime_seconds` (`int`): Lifetime of reset password token. **Defaults to 3600**.
-* `after_forgot_password`: Optional function called after a successful forgot password request. See below.
-
-## After forgot password
-
-You can provide a custom function to be called after a successful forgot password request. It is called with **three arguments**:
-
-* The **user** which has requested to reset their password.
-* A ready-to-use **JWT token** that will be accepted by the reset password route.
-* The original **`Request` object**.
-
-Typically, you'll want to **send an e-mail** with the link (and the token) that allows the user to reset their password.
-
-You can define it as an `async` or standard method.
-
-Example:
-
-```py
-def on_after_forgot_password(user: UserDB, token: str, request: Request):
- print(f"User {user.id} has forgot their password. Reset token: {token}")
-
-app.include_router(
- fastapi_users.get_reset_password_router("SECRET", after_forgot_password=on_after_forgot_password),
- prefix="/auth",
- tags=["auth"],
-)
-```
-
-## After reset password
-
-You can provide a custom function to be called after a successful password reset. It is called with **two arguments**:
-
-* The **user** which has reset their password.
-* The original **`Request` object**.
-
-For example, you may want to **send an e-mail** to the concerned user to warn him that their password has been changed and that they should take action if they think they have been hacked.
-
-You can define it as an `async` or standard method.
-
-Example:
-
-```py
-def on_after_reset_password(user: UserDB, request: Request):
- print(f"User {user.id} has reset their password.")
-
-app.include_router(
- fastapi_users.get_reset_password_router("SECRET", after_reset_password=on_after_reset_password),
+ fastapi_users.get_reset_password_router(),
prefix="/auth",
tags=["auth"],
)
diff --git a/docs/configuration/routers/users.md b/docs/configuration/routers/users.md
index df856c91..09f072b9 100644
--- a/docs/configuration/routers/users.md
+++ b/docs/configuration/routers/users.md
@@ -8,9 +8,13 @@ This router provides routes to manage users. Check the [routes usage](../../usag
from fastapi import FastAPI
from fastapi_users import FastAPIUsers
+SECRET = "SECRET"
+
+jwt_authentication = JWTAuthentication(secret=SECRET, lifetime_seconds=3600)
+
fastapi_users = FastAPIUsers(
- user_db,
- auth_backends,
+ get_user_manager,
+ [jwt_authentication],
User,
UserCreate,
UserUpdate,
@@ -36,28 +40,3 @@ app.include_router(
tags=["users"],
)
```
-
-## After update
-
-You can provide a custom function to be called after a successful update user request. It is called with **three arguments**:
-
-* The **user** which was updated.
-* The dictionary containing the updated fields.
-* The original **`Request` object**.
-
-It may be useful, for example, if you wish to update your user in a data analytics or customer success platform.
-
-You can define it as an `async` or standard method.
-
-Example:
-
-```py
-def on_after_update(user: UserDB, updated_user_data: Dict[str, Any], request: Request):
- print(f"User {user.id} has been updated with the following data: {updated_user_data}")
-
-app.include_router(
- fastapi_users.get_users_router(on_after_update),
- prefix="/users",
- tags=["users"],
-)
-```
diff --git a/docs/configuration/routers/verify.md b/docs/configuration/routers/verify.md
index 70d14d73..2650b8b5 100644
--- a/docs/configuration/routers/verify.md
+++ b/docs/configuration/routers/verify.md
@@ -11,9 +11,13 @@ This router provides routes to manage user email verification. Check the [routes
from fastapi import FastAPI
from fastapi_users import FastAPIUsers
+SECRET = "SECRET"
+
+jwt_authentication = JWTAuthentication(secret=SECRET, lifetime_seconds=3600)
+
fastapi_users = FastAPIUsers(
- user_db,
- auth_backends,
+ get_user_manager,
+ [jwt_authentication],
User,
UserCreate,
UserUpdate,
@@ -22,63 +26,7 @@ fastapi_users = FastAPIUsers(
app = FastAPI()
app.include_router(
- fastapi_users.get_verify_router("SECRET"),
- prefix="/auth",
- tags=["auth"],
-)
-```
-
-Parameters:
-
-* `verification_token_secret` (`Union[str, pydantic.SecretStr]`): Secret to encode verify token.
-* `verification_token_lifetime_seconds` (`int`): Lifetime of verify token. **Defaults to 3600**.
-* `after_verification_request`: Optional function called after a successful verify request. See below.
-* `after_verification`: Optional function called after a successful verification. See below.
-
-## After verification request
-
-You can provide a custom function to be called after a successful verification request. It is called with **three arguments**:
-
-* The **user** for which the verification has been requested.
-* A ready-to-use **JWT token** that will be accepted by the verify route.
-* The original **`Request` object**.
-
-Typically, you'll want to **send an e-mail** with the link (and the token) that allows the user to verify their e-mail.
-
-You can define it as an `async` or standard method.
-
-Example:
-
-```py
-def after_verification_request(user: UserDB, token: str, request: Request):
- print(f"Verification requested for user {user.id}. Verification token: {token}")
-
-app.include_router(
- fastapi_users.get_verify_router("SECRET", after_verification_request=after_verification_request),
- prefix="/auth",
- tags=["auth"],
-)
-```
-
-## After verification
-
-You can provide a custom function to be called after a successful user verification. It is called with **two arguments**:
-
-* The **user** that has been verified.
-* The original **`Request` object**.
-
-This may be useful if you wish to send another e-mail or store this information in a data analytics or customer success platform.
-
-You can define it as an `async` or standard method.
-
-Example:
-
-```py
-def after_verification(user: UserDB, request: Request):
- print(f"{user.id} is now verified.")
-
-app.include_router(
- fastapi_users.get_verify_router("SECRET", after_verification=after_verification),
+ fastapi_users.get_verify_router(),
prefix="/auth",
tags=["auth"],
)
diff --git a/docs/configuration/user-manager.md b/docs/configuration/user-manager.md
new file mode 100644
index 00000000..cd06ea35
--- /dev/null
+++ b/docs/configuration/user-manager.md
@@ -0,0 +1,227 @@
+# UserManager
+
+The `UserManager` class is the core logic of FastAPI Users. We provide the `BaseUserManager` class which you should extend to set some parameters and define logic, for example when a user just registered or forgot its password.
+
+It's designed to be easily extensible and customizable so that you can integrate less generic logic.
+
+## Create your `UserManager` class
+
+You should define your own version of the `UserManager` class to set various parameters.
+
+```py hl_lines="13-29"
+{!./src/user_manager.py!}
+```
+
+As you can see, you have to define here various attributes and methods. You can find the complete list of those below.
+
+## Create `get_user_manager` dependency
+
+The `UserManager` class will be injected at runtime using a FastAPI dependency. This way, you can run it in a database session or swap it with a mock during testing.
+
+```py hl_lines="31-32"
+{!./src/user_manager.py!}
+```
+
+Notice that we use the `get_user_db` dependency we defined earlier to inject the database instance.
+
+## Customize attributes and methods
+
+### Attributes
+
+* `user_db_model`: Pydantic model of a DB representation of a user.
+* `reset_password_token_secret`: Secret to encode reset password token. **Use a strong passphrase and keep it secure.**
+* `reset_password_token_lifetime_seconds`: Lifetime of reset password token. Defaults to 3600.
+* `reset_password_token_audience`: JWT audience of reset password token. Defaults to `fastapi-users:reset`.
+* `verification_token_secret`: Secret to encode verification token. **Use a strong passphrase and keep it secure.**
+* `verification_token_lifetime_seconds`: Lifetime of verification token. Defaults to 3600.
+* `verification_token_audience`: JWT audience of verification token. Defaults to `fastapi-users:verify`.
+
+### Methods
+
+#### `validate_password`
+
+Validate a password.
+
+**Arguments**
+
+* `password` (`str`): the password to validate.
+* `user` (`Union[UserCreate, User]`): user model which we are currently validating the password. Useful if you want to check that the password doesn't contain the name or the birthdate of the user for example.
+
+**Output**
+
+This function should return `None` if the password is valid or raise `InvalidPasswordException` if not. This exception expects an argument `reason` telling why the password is invalid. It'll be part of the error response.
+
+**Example**
+
+```py
+from fastapi_users import BaseUserManager, InvalidPasswordException
+
+
+class UserManager(BaseUserManager[UserCreate, UserDB]):
+ # ...
+ async def validate_password(
+ self,
+ password: str,
+ user: Union[UserCreate, UserDB],
+ ) -> None:
+ if len(password) < 8:
+ raise InvalidPasswordException(
+ reason="Password should be at least 8 characters"
+ )
+ if user.email in password:
+ raise InvalidPasswordException(
+ reason="Password should not contain e-mail"
+ )
+```
+
+#### `on_after_register`
+
+Perform logic after successful user registration.
+
+Typically, you'll want to **send a welcome e-mail** or add it to your marketing analytics pipeline.
+
+**Arguments**
+
+* `user` (`UserDB`): the registered user.
+* `request` (`Optional[Request]`): optional FastAPI request object that triggered the operation. Defaults to None.
+
+**Example**
+
+```py
+from fastapi_users import BaseUserManager
+
+
+class UserManager(BaseUserManager[UserCreate, UserDB]):
+ # ...
+ async def on_after_register(self, user: UserDB, request: Optional[Request] = None):
+ print(f"User {user.id} has registered.")
+```
+
+#### `on_after_update`
+
+Perform logic after successful user update.
+
+It may be useful, for example, if you wish to update your user in a data analytics or customer success platform.
+
+**Arguments**
+
+* `user` (`UserDB`): the updated user.
+* `update_dict` (`Dict[str, Any]`): dictionary with the updated user fields.
+* `request` (`Optional[Request]`): optional FastAPI request object that triggered the operation. Defaults to None.
+
+**Example**
+
+```py
+from fastapi_users import BaseUserManager
+
+
+class UserManager(BaseUserManager[UserCreate, UserDB]):
+ # ...
+ async def on_after_update(
+ self,
+ user: UserDB,
+ update_dict: Dict[str, Any],
+ request: Optional[Request] = None,
+ ):
+ print(f"User {user.id} has been updated with {update_dict}.")
+```
+
+#### `on_after_request_verify`
+
+Perform logic after successful verification request.
+
+Typically, you'll want to **send an e-mail** with the link (and the token) that allows the user to verify their e-mail.
+
+**Arguments**
+
+* `user` (`UserDB`): the user to verify.
+* `token` (`str`): the verification token.
+* `request` (`Optional[Request]`): optional FastAPI request object that triggered the operation. Defaults to None.
+
+**Example**
+
+```py
+from fastapi_users import BaseUserManager
+
+
+class UserManager(BaseUserManager[UserCreate, UserDB]):
+ # ...
+ async def on_after_request_verify(
+ self, user: UserDB, token: str, request: Optional[Request] = None
+ ):
+ print(f"Verification requested for user {user.id}. Verification token: {token}")
+```
+
+#### `on_after_verify`
+
+Perform logic after successful user verification.
+
+This may be useful if you wish to send another e-mail or store this information in a data analytics or customer success platform.
+
+**Arguments**
+
+* `user` (`UserDB`): the verified user.
+* `request` (`Optional[Request]`): optional FastAPI request object that triggered the operation. Defaults to None.
+
+**Example**
+
+```py
+from fastapi_users import BaseUserManager
+
+
+class UserManager(BaseUserManager[UserCreate, UserDB]):
+ # ...
+ async def on_after_request_verify(
+ self, user: UserDB, request: Optional[Request] = None
+ ):
+ print(f"User {user.id} has been verified")
+```
+
+#### `on_after_forgot_password`
+
+Perform logic after successful forgot password request.
+
+Typically, you'll want to **send an e-mail** with the link (and the token) that allows the user to reset their password.
+
+**Arguments**
+
+* `user` (`UserDB`): the user that forgot its password.
+* `token` (`str`): the forgot password token
+* `request` (`Optional[Request]`): optional FastAPI request object that triggered the operation. Defaults to None.
+
+**Example**
+
+```py
+from fastapi_users import BaseUserManager
+
+
+class UserManager(BaseUserManager[UserCreate, UserDB]):
+ # ...
+ async def on_after_request_verify(
+ self, user: UserDB, token: str, request: Optional[Request] = None
+ ):
+ print(f"User {user.id} has forgot their password. Reset token: {token}")
+```
+
+#### `on_after_reset_password`
+
+Perform logic after successful password reset.
+
+For example, you may want to **send an e-mail** to the concerned user to warn him that their password has been changed and that they should take action if they think they have been hacked.
+
+**Arguments**
+
+* `user` (`UserDB`): the user that reset its password.
+* `request` (`Optional[Request]`): optional FastAPI request object that triggered the operation. Defaults to None.
+
+**Example**
+
+```py
+from fastapi_users import BaseUserManager
+
+
+class UserManager(BaseUserManager[UserCreate, UserDB]):
+ # ...
+ async def on_after_reset_password(self, user: UserDB, request: Optional[Request] = None):
+ print(f"User {user.id} has reset their password.")
+```
diff --git a/docs/installation.md b/docs/installation.md
index 42d974cb..d60712fd 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -28,4 +28,4 @@ pip install 'fastapi-users[ormar]'
---
-That's it! Now, let's have a look at our [User model](./configuration/model.md).
+That's it! Now, let's have a look at our [User model](./configuration/models.md).
diff --git a/docs/src/db_mongodb.py b/docs/src/db_mongodb.py
index 1281e898..2f6c1886 100644
--- a/docs/src/db_mongodb.py
+++ b/docs/src/db_mongodb.py
@@ -1,24 +1,7 @@
import motor.motor_asyncio
-from fastapi import FastAPI
-from fastapi_users import models
from fastapi_users.db import MongoDBUserDatabase
-
-class User(models.BaseUser):
- pass
-
-
-class UserCreate(models.BaseUserCreate):
- pass
-
-
-class UserUpdate(User, models.BaseUserUpdate):
- pass
-
-
-class UserDB(User, models.BaseUserDB):
- pass
-
+from .models import UserDB
DATABASE_URL = "mongodb://localhost:27017"
client = motor.motor_asyncio.AsyncIOMotorClient(
@@ -28,7 +11,5 @@ db = client["database_name"]
collection = db["users"]
-app = FastAPI()
-
-
-user_db = MongoDBUserDatabase(UserDB, collection)
+def get_user_db():
+ yield MongoDBUserDatabase(UserDB, collection)
diff --git a/docs/src/db_ormar.py b/docs/src/db_ormar.py
index c13b6dc1..bb699938 100644
--- a/docs/src/db_ormar.py
+++ b/docs/src/db_ormar.py
@@ -1,26 +1,8 @@
import databases
import sqlalchemy
-from fastapi import FastAPI
-from fastapi_users import models
from fastapi_users.db import OrmarBaseUserModel, OrmarUserDatabase
-class User(models.BaseUser):
- pass
-
-
-class UserCreate(models.BaseUserCreate):
- pass
-
-
-class UserUpdate(User, models.BaseUserUpdate):
- pass
-
-
-class UserDB(User, models.BaseUserDB):
- pass
-
-
DATABASE_URL = "sqlite:///test.db"
metadata = sqlalchemy.MetaData()
database = databases.Database(DATABASE_URL)
@@ -37,20 +19,5 @@ engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.create_all(engine)
-user_db = OrmarUserDatabase(UserDB, UserModel)
-app = FastAPI()
-app.state.database = database
-
-
-@app.on_event("startup")
-async def startup() -> None:
- database_ = app.state.database
- if not database_.is_connected:
- await database_.connect()
-
-
-@app.on_event("shutdown")
-async def shutdown() -> None:
- database_ = app.state.database
- if database_.is_connected:
- await database_.disconnect()
+def get_user_db():
+ yield OrmarUserDatabase(UserDB, UserModel)
diff --git a/docs/src/db_sqlalchemy.py b/docs/src/db_sqlalchemy.py
index 00f02df2..adc8b196 100644
--- a/docs/src/db_sqlalchemy.py
+++ b/docs/src/db_sqlalchemy.py
@@ -1,31 +1,12 @@
import databases
import sqlalchemy
-from fastapi import FastAPI
-from fastapi_users import models
from fastapi_users.db import SQLAlchemyBaseUserTable, SQLAlchemyUserDatabase
from sqlalchemy.ext.declarative import DeclarativeMeta, declarative_base
-
-class User(models.BaseUser):
- pass
-
-
-class UserCreate(models.BaseUserCreate):
- pass
-
-
-class UserUpdate(User, models.BaseUserUpdate):
- pass
-
-
-class UserDB(User, models.BaseUserDB):
- pass
-
+from .models import UserDB
DATABASE_URL = "sqlite:///./test.db"
-
database = databases.Database(DATABASE_URL)
-
Base: DeclarativeMeta = declarative_base()
@@ -36,20 +17,10 @@ class UserTable(Base, SQLAlchemyBaseUserTable):
engine = sqlalchemy.create_engine(
DATABASE_URL, connect_args={"check_same_thread": False}
)
-
Base.metadata.create_all(engine)
users = UserTable.__table__
-user_db = SQLAlchemyUserDatabase(UserDB, database, users)
-
-app = FastAPI()
-@app.on_event("startup")
-async def startup():
- await database.connect()
-
-
-@app.on_event("shutdown")
-async def shutdown():
- await database.disconnect()
+def get_user_db():
+ yield SQLAlchemyUserDatabase(UserDB, database, users)
diff --git a/docs/src/db_tortoise.py b/docs/src/db_tortoise.py
deleted file mode 100644
index 6e8883f0..00000000
--- a/docs/src/db_tortoise.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from fastapi import FastAPI
-from fastapi_users import models
-from fastapi_users.db import TortoiseBaseUserModel, TortoiseUserDatabase
-from tortoise.contrib.fastapi import register_tortoise
-from tortoise.contrib.pydantic import PydanticModel
-
-
-class UserModel(TortoiseBaseUserModel):
- pass
-
-
-class User(models.BaseUser):
- pass
-
-
-class UserCreate(models.BaseUserCreate):
- pass
-
-
-class UserUpdate(User, models.BaseUserUpdate):
- pass
-
-
-class UserDB(User, models.BaseUserDB, PydanticModel):
- class Config:
- orm_mode = True
- orig_model = UserModel
-
-
-DATABASE_URL = "sqlite://./test.db"
-
-user_db = TortoiseUserDatabase(UserDB, UserModel)
-app = FastAPI()
-
-register_tortoise(
- app,
- db_url=DATABASE_URL,
- modules={"models": ["path_to_your_package"]},
- generate_schemas=True,
-)
diff --git a/docs/src/db_tortoise_adapter.py b/docs/src/db_tortoise_adapter.py
new file mode 100644
index 00000000..01b06e7f
--- /dev/null
+++ b/docs/src/db_tortoise_adapter.py
@@ -0,0 +1,9 @@
+from fastapi_users.db import TortoiseUserDatabase
+
+from .models import UserDB, UserModel
+
+DATABASE_URL = "sqlite://./test.db"
+
+
+def get_user_db():
+ yield TortoiseUserDatabase(UserDB, UserModel)
diff --git a/docs/src/db_tortoise_model.py b/docs/src/db_tortoise_model.py
new file mode 100644
index 00000000..e55ecc42
--- /dev/null
+++ b/docs/src/db_tortoise_model.py
@@ -0,0 +1,25 @@
+from fastapi_users import models
+from fastapi_users.db import TortoiseBaseUserModel
+from tortoise.contrib.pydantic import PydanticModel
+
+
+class User(models.BaseUser):
+ pass
+
+
+class UserCreate(models.BaseUserCreate):
+ pass
+
+
+class UserUpdate(models.BaseUserUpdate):
+ pass
+
+
+class UserModel(TortoiseBaseUserModel):
+ pass
+
+
+class UserDB(User, models.BaseUserDB, PydanticModel):
+ class Config:
+ orm_mode = True
+ orig_model = UserModel
diff --git a/docs/src/full_mongodb.py b/docs/src/full_mongodb.py
deleted file mode 100644
index fadad450..00000000
--- a/docs/src/full_mongodb.py
+++ /dev/null
@@ -1,80 +0,0 @@
-import motor.motor_asyncio
-from fastapi import FastAPI, Request
-from fastapi_users import FastAPIUsers, models
-from fastapi_users.authentication import JWTAuthentication
-from fastapi_users.db import MongoDBUserDatabase
-
-DATABASE_URL = "mongodb://localhost:27017"
-SECRET = "SECRET"
-
-
-class User(models.BaseUser):
- pass
-
-
-class UserCreate(models.BaseUserCreate):
- pass
-
-
-class UserUpdate(User, models.BaseUserUpdate):
- pass
-
-
-class UserDB(User, models.BaseUserDB):
- pass
-
-
-client = motor.motor_asyncio.AsyncIOMotorClient(
- DATABASE_URL, uuidRepresentation="standard"
-)
-db = client["database_name"]
-collection = db["users"]
-user_db = MongoDBUserDatabase(UserDB, collection)
-
-
-def on_after_register(user: UserDB, request: Request):
- print(f"User {user.id} has registered.")
-
-
-def on_after_forgot_password(user: UserDB, token: str, request: Request):
- print(f"User {user.id} has forgot their password. Reset token: {token}")
-
-
-def after_verification_request(user: UserDB, token: str, request: Request):
- print(f"Verification requested for user {user.id}. Verification token: {token}")
-
-
-jwt_authentication = JWTAuthentication(
- secret=SECRET, lifetime_seconds=3600, tokenUrl="auth/jwt/login"
-)
-
-app = FastAPI()
-fastapi_users = FastAPIUsers(
- user_db,
- [jwt_authentication],
- User,
- UserCreate,
- UserUpdate,
- UserDB,
-)
-app.include_router(
- fastapi_users.get_auth_router(jwt_authentication), prefix="/auth/jwt", tags=["auth"]
-)
-app.include_router(
- fastapi_users.get_register_router(on_after_register), prefix="/auth", tags=["auth"]
-)
-app.include_router(
- fastapi_users.get_reset_password_router(
- SECRET, after_forgot_password=on_after_forgot_password
- ),
- prefix="/auth",
- tags=["auth"],
-)
-app.include_router(
- fastapi_users.get_verify_router(
- SECRET, after_verification_request=after_verification_request
- ),
- prefix="/auth",
- tags=["auth"],
-)
-app.include_router(fastapi_users.get_users_router(), prefix="/users", tags=["users"])
diff --git a/docs/src/full_ormar.py b/docs/src/full_ormar.py
deleted file mode 100644
index c2eada18..00000000
--- a/docs/src/full_ormar.py
+++ /dev/null
@@ -1,105 +0,0 @@
-import databases
-import sqlalchemy
-from fastapi import FastAPI, Request
-from fastapi_users import FastAPIUsers, models
-from fastapi_users.authentication import JWTAuthentication
-from fastapi_users.db import OrmarBaseUserModel, OrmarUserDatabase
-
-DATABASE_URL = "sqlite:///test.db"
-SECRET = "SECRET"
-metadata = sqlalchemy.MetaData()
-database = databases.Database(DATABASE_URL)
-
-
-class User(models.BaseUser):
- pass
-
-
-class UserCreate(models.BaseUserCreate):
- pass
-
-
-class UserUpdate(User, models.BaseUserUpdate):
- pass
-
-
-class UserDB(User, models.BaseUserDB):
- pass
-
-
-class UserModel(OrmarBaseUserModel):
- class Meta:
- tablename = "users"
- metadata = metadata
- database = database
-
-
-engine = sqlalchemy.create_engine(DATABASE_URL)
-metadata.create_all(engine)
-
-
-user_db = OrmarUserDatabase(UserDB, UserModel)
-
-
-def on_after_register(user: UserDB, request: Request):
- print(f"User {user.id} has registered.")
-
-
-def on_after_forgot_password(user: UserDB, token: str, request: Request):
- print(f"User {user.id} has forgot their password. Reset token: {token}")
-
-
-def after_verification_request(user: UserDB, token: str, request: Request):
- print(f"Verification requested for user {user.id}. Verification token: {token}")
-
-
-jwt_authentication = JWTAuthentication(
- secret=SECRET, lifetime_seconds=3600, tokenUrl="auth/jwt/login"
-)
-
-app = FastAPI()
-fastapi_users = FastAPIUsers(
- user_db,
- [jwt_authentication],
- User,
- UserCreate,
- UserUpdate,
- UserDB,
-)
-app.include_router(
- fastapi_users.get_auth_router(jwt_authentication), prefix="/auth/jwt", tags=["auth"]
-)
-app.include_router(
- fastapi_users.get_register_router(on_after_register), prefix="/auth", tags=["auth"]
-)
-app.include_router(
- fastapi_users.get_reset_password_router(
- SECRET, after_forgot_password=on_after_forgot_password
- ),
- prefix="/auth",
- tags=["auth"],
-)
-app.include_router(
- fastapi_users.get_verify_router(
- SECRET, after_verification_request=after_verification_request
- ),
- prefix="/auth",
- tags=["auth"],
-)
-app.include_router(fastapi_users.get_users_router(), prefix="/users", tags=["users"])
-
-app.state.database = database
-
-
-@app.on_event("startup")
-async def startup() -> None:
- database_ = app.state.database
- if not database_.is_connected:
- await database_.connect()
-
-
-@app.on_event("shutdown")
-async def shutdown() -> None:
- database_ = app.state.database
- if database_.is_connected:
- await database_.disconnect()
diff --git a/docs/src/full_sqlalchemy.py b/docs/src/full_sqlalchemy.py
deleted file mode 100644
index 3302a6f7..00000000
--- a/docs/src/full_sqlalchemy.py
+++ /dev/null
@@ -1,101 +0,0 @@
-import databases
-import sqlalchemy
-from fastapi import FastAPI, Request
-from fastapi_users import FastAPIUsers, models
-from fastapi_users.authentication import JWTAuthentication
-from fastapi_users.db import SQLAlchemyBaseUserTable, SQLAlchemyUserDatabase
-from sqlalchemy.ext.declarative import DeclarativeMeta, declarative_base
-
-DATABASE_URL = "sqlite:///./test.db"
-SECRET = "SECRET"
-
-
-class User(models.BaseUser):
- pass
-
-
-class UserCreate(models.BaseUserCreate):
- pass
-
-
-class UserUpdate(User, models.BaseUserUpdate):
- pass
-
-
-class UserDB(User, models.BaseUserDB):
- pass
-
-
-database = databases.Database(DATABASE_URL)
-Base: DeclarativeMeta = declarative_base()
-
-
-class UserTable(Base, SQLAlchemyBaseUserTable):
- pass
-
-
-engine = sqlalchemy.create_engine(
- DATABASE_URL, connect_args={"check_same_thread": False}
-)
-Base.metadata.create_all(engine)
-
-users = UserTable.__table__
-user_db = SQLAlchemyUserDatabase(UserDB, database, users)
-
-
-def on_after_register(user: UserDB, request: Request):
- print(f"User {user.id} has registered.")
-
-
-def on_after_forgot_password(user: UserDB, token: str, request: Request):
- print(f"User {user.id} has forgot their password. Reset token: {token}")
-
-
-def after_verification_request(user: UserDB, token: str, request: Request):
- print(f"Verification requested for user {user.id}. Verification token: {token}")
-
-
-jwt_authentication = JWTAuthentication(
- secret=SECRET, lifetime_seconds=3600, tokenUrl="auth/jwt/login"
-)
-
-app = FastAPI()
-fastapi_users = FastAPIUsers(
- user_db,
- [jwt_authentication],
- User,
- UserCreate,
- UserUpdate,
- UserDB,
-)
-app.include_router(
- fastapi_users.get_auth_router(jwt_authentication), prefix="/auth/jwt", tags=["auth"]
-)
-app.include_router(
- fastapi_users.get_register_router(on_after_register), prefix="/auth", tags=["auth"]
-)
-app.include_router(
- fastapi_users.get_reset_password_router(
- SECRET, after_forgot_password=on_after_forgot_password
- ),
- prefix="/auth",
- tags=["auth"],
-)
-app.include_router(
- fastapi_users.get_verify_router(
- SECRET, after_verification_request=after_verification_request
- ),
- prefix="/auth",
- tags=["auth"],
-)
-app.include_router(fastapi_users.get_users_router(), prefix="/users", tags=["users"])
-
-
-@app.on_event("startup")
-async def startup():
- await database.connect()
-
-
-@app.on_event("shutdown")
-async def shutdown():
- await database.disconnect()
diff --git a/docs/src/full_tortoise.py b/docs/src/full_tortoise.py
deleted file mode 100644
index d6f2679e..00000000
--- a/docs/src/full_tortoise.py
+++ /dev/null
@@ -1,88 +0,0 @@
-from fastapi import FastAPI, Request
-from fastapi_users import FastAPIUsers, models
-from fastapi_users.authentication import JWTAuthentication
-from fastapi_users.db import TortoiseBaseUserModel, TortoiseUserDatabase
-from tortoise.contrib.fastapi import register_tortoise
-from tortoise.contrib.pydantic import PydanticModel
-
-DATABASE_URL = "sqlite://./test.db"
-SECRET = "SECRET"
-
-
-class UserModel(TortoiseBaseUserModel):
- pass
-
-
-class User(models.BaseUser):
- pass
-
-
-class UserCreate(models.BaseUserCreate):
- pass
-
-
-class UserUpdate(User, models.BaseUserUpdate):
- pass
-
-
-class UserDB(User, models.BaseUserDB, PydanticModel):
- class Config:
- orm_mode = True
- orig_model = UserModel
-
-
-user_db = TortoiseUserDatabase(UserDB, UserModel)
-app = FastAPI()
-register_tortoise(
- app,
- db_url=DATABASE_URL,
- modules={"models": ["full_tortoise"]},
- generate_schemas=True,
-)
-
-
-def on_after_register(user: UserDB, request: Request):
- print(f"User {user.id} has registered.")
-
-
-def on_after_forgot_password(user: UserDB, token: str, request: Request):
- print(f"User {user.id} has forgot their password. Reset token: {token}")
-
-
-def after_verification_request(user: UserDB, token: str, request: Request):
- print(f"Verification requested for user {user.id}. Verification token: {token}")
-
-
-jwt_authentication = JWTAuthentication(
- secret=SECRET, lifetime_seconds=3600, tokenUrl="auth/jwt/login"
-)
-
-fastapi_users = FastAPIUsers(
- user_db,
- [jwt_authentication],
- User,
- UserCreate,
- UserUpdate,
- UserDB,
-)
-app.include_router(
- fastapi_users.get_auth_router(jwt_authentication), prefix="/auth/jwt", tags=["auth"]
-)
-app.include_router(
- fastapi_users.get_register_router(on_after_register), prefix="/auth", tags=["auth"]
-)
-app.include_router(
- fastapi_users.get_reset_password_router(
- SECRET, after_forgot_password=on_after_forgot_password
- ),
- prefix="/auth",
- tags=["auth"],
-)
-app.include_router(
- fastapi_users.get_verify_router(
- SECRET, after_verification_request=after_verification_request
- ),
- prefix="/auth",
- tags=["auth"],
-)
-app.include_router(fastapi_users.get_users_router(), prefix="/users", tags=["users"])
diff --git a/docs/src/user_manager.py b/docs/src/user_manager.py
new file mode 100644
index 00000000..296a9ab7
--- /dev/null
+++ b/docs/src/user_manager.py
@@ -0,0 +1,32 @@
+from typing import Optional
+
+from fastapi import Depends, Request
+from fastapi_users import BaseUserManager
+
+from .db import get_user_db
+from .models import UserCreate, UserDB
+
+SECRET = "SECRET"
+
+
+class UserManager(BaseUserManager[UserCreate, UserDB]):
+ user_db_model = UserDB
+ reset_password_token_secret = SECRET
+ verification_token_secret = SECRET
+
+ async def on_after_register(self, user: UserDB, request: Optional[Request] = None):
+ print(f"User {user.id} has registered.")
+
+ async def on_after_forgot_password(
+ self, user: UserDB, token: str, request: Optional[Request] = None
+ ):
+ print(f"User {user.id} has forgot their password. Reset token: {token}")
+
+ async def on_after_request_verify(
+ self, user: UserDB, token: str, request: Optional[Request] = None
+ ):
+ print(f"Verification requested for user {user.id}. Verification token: {token}")
+
+
+def get_user_manager(user_db=Depends(get_user_db)):
+ yield UserManager(user_db)
diff --git a/docs/usage/helpers.md b/docs/usage/helpers.md
deleted file mode 100644
index 3dbda8a1..00000000
--- a/docs/usage/helpers.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Helpers
-
-**FastAPI Users** provides some helper functions to perform some actions programmatically. They are available from your `FastAPIUsers` instance.
-
-## Create user
-
-Create a user.
-
-```py
-regular_user = await fastapi_users.create_user(
- UserCreate(
- email="king.arthur@camelot.bt",
- password="guinevere",
- )
-)
-
-superuser = await fastapi_users.create_user(
- UserCreate(
- email="king.arthur@camelot.bt",
- password="guinevere",
- is_superuser=True,
- )
-)
-```
-
-## Verify user
-
-Verify a user.
-
-```py
-verified_user = await fastapi_users.verify_user(non_verified_user)
-assert verified_user.is_verified is True
-```
-
-## Get user
-
-Retrieve a user by e-mail.
-
-```py
-user = await fastapi_users.get_user("king.arthur@camelot.bt")
-```
diff --git a/mkdocs.yml b/mkdocs.yml
index a093408c..5d64d4d1 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -31,39 +31,53 @@ markdown_extensions:
permalink: true
- admonition
- codehilite
- - pymdownx.superfences
+ - pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:mermaid2.fence_mermaid
- pymdownx.tasklist
- pymdownx.tabbed
+plugins:
+ - search
+ - mermaid2:
+ arguments:
+ theme: |
+ ^(JSON.parse(window.localStorage.getItem('/.__palette')).index == 1) ? 'dark' : 'light'
+
+extra_javascript:
+ - https://unpkg.com/mermaid/dist/mermaid.min.js
+
nav:
- About: index.md
- installation.md
- Configuration:
- - configuration/model.md
- - Databases:
+ - configuration/overview.md
+ - configuration/models.md
+ - Database adapters:
- configuration/databases/sqlalchemy.md
- configuration/databases/mongodb.md
- configuration/databases/tortoise.md
- configuration/databases/ormar.md
- - Authentication:
+ - Authentication backends:
- Introduction: configuration/authentication/index.md
- configuration/authentication/jwt.md
- configuration/authentication/cookie.md
+ - configuration/user-manager.md
- Routers:
- Introduction: configuration/routers/index.md
- configuration/routers/auth.md
- configuration/routers/register.md
+ - configuration/routers/verify.md
- configuration/routers/reset.md
- configuration/routers/users.md
- - configuration/routers/verify.md
- - configuration/password-validation.md
- configuration/full-example.md
- configuration/oauth.md
- Usage:
- usage/flow.md
- usage/routes.md
- usage/current-user.md
- - usage/helpers.md
- Migration:
- migration/08_to_1x.md
- migration/1x_to_2x.md
diff --git a/requirements.dev.txt b/requirements.dev.txt
index 7f7a99b0..1b05ad76 100644
--- a/requirements.dev.txt
+++ b/requirements.dev.txt
@@ -8,6 +8,7 @@ pytest-asyncio
flake8-docstrings
mkdocs
mkdocs-material
+mkdocs-mermaid2-plugin
black
mypy
codecov