Allow to set is_verified to True after OAuth callback

This commit is contained in:
François Voron
2023-02-13 17:42:31 +01:00
parent 5c48283155
commit 9b57fa2e73
4 changed files with 53 additions and 0 deletions

View File

@@ -121,6 +121,31 @@ app.include_router(
Notice that, just like for the [Users router](./routers/users.md), you have to pass the `UserRead` Pydantic schema.
#### Set `is_verified` to `True` by default
!!! tip "This section is only useful if you set up email verification"
You can read more about this feature [here](./routers/verify.md).
When a new user registers with an OAuth provider, the `is_verified` flag is set to `False`, which requires the user to verify its email address.
You can choose to trust the email address given by the OAuth provider and set the `is_verified` flag to `True` after registration. You can do this by setting the `is_verified_by_default` argument:
```py
app.include_router(
fastapi_users.get_oauth_router(
google_oauth_client,
auth_backend,
"SECRET",
is_verified_by_default=True,
),
prefix="/auth/google",
tags=["auth"],
)
```
!!! danger "Make sure you can trust the OAuth provider"
Make sure the OAuth provider you're using **does verify** the email address before enabling this flag.
### Full example
!!! warning

View File

@@ -157,6 +157,7 @@ class BaseUserManager(Generic[models.UP, models.ID]):
request: Optional[Request] = None,
*,
associate_by_email: bool = False,
is_verified_by_default: bool = False,
) -> models.UOAP:
"""
Handle the callback after a successful OAuth authentication.
@@ -181,6 +182,10 @@ class BaseUserManager(Generic[models.UP, models.ID]):
triggered the operation, defaults to None
:param associate_by_email: If True, any existing user with the same
e-mail address will be associated to this user. Defaults to False.
:param is_verified_by_default: If True, the `is_verified` flag will be
set to `True` on newly created user. Make sure the OAuth Provider you're
using does verify the email address before enabling this flag.
Defaults to False.
:return: A user.
"""
oauth_account_dict = {
@@ -207,6 +212,7 @@ class BaseUserManager(Generic[models.UP, models.ID]):
user_dict = {
"email": account_email,
"hashed_password": self.password_helper.hash(password),
"is_verified": is_verified_by_default,
}
user = await self.user_db.create(user_dict)
user = await self.user_db.add_oauth_account(user, oauth_account_dict)

View File

@@ -34,6 +34,7 @@ def get_oauth_router(
state_secret: SecretType,
redirect_url: Optional[str] = None,
associate_by_email: bool = False,
is_verified_by_default: bool = False,
) -> APIRouter:
"""Generate a router with the OAuth routes."""
router = APIRouter()
@@ -132,6 +133,7 @@ def get_oauth_router(
token.get("refresh_token"),
request,
associate_by_email=associate_by_email,
is_verified_by_default=is_verified_by_default,
)
except UserAlreadyExists:
raise HTTPException(

View File

@@ -240,6 +240,26 @@ class TestOAuthCallback:
assert user.email == "galahad@camelot.bt"
assert len(user.oauth_accounts) == 1
assert user.oauth_accounts[0].id is not None
assert user.is_verified is False
assert user_manager_oauth.on_after_register.called is True
async def test_new_user_is_verified_by_default(
self, user_manager_oauth: UserManagerMock[UserOAuthModel]
):
user = await user_manager_oauth.oauth_callback(
"service1",
"TOKEN",
"new_user_oauth1",
"galahad@camelot.bt",
1579000751,
is_verified_by_default=True,
)
assert user.email == "galahad@camelot.bt"
assert len(user.oauth_accounts) == 1
assert user.oauth_accounts[0].id is not None
assert user.is_verified is True
assert user_manager_oauth.on_after_register.called is True