mirror of
https://github.com/fastapi-users/fastapi-users.git
synced 2025-08-14 18:58:10 +08:00
Add docs for OAuth association router
This commit is contained in:
@ -65,7 +65,7 @@ The advantage of MongoDB is that you can easily embed sub-objects in a single do
|
||||
|
||||
It's worth to note that `OAuthAccount` is **not a Beanie document** but a Pydantic model that we'll embed inside the `User` document, through the `oauth_accounts` array.
|
||||
|
||||
### Generate a router
|
||||
### Generate routers
|
||||
|
||||
Once you have a `FastAPIUsers` instance, you can make it generate a single OAuth router for a given client **and** authentication backend.
|
||||
|
||||
@ -77,6 +77,50 @@ app.include_router(
|
||||
)
|
||||
```
|
||||
|
||||
!!! tip
|
||||
If you have several OAuth clients and/or several authentication backends, you'll need to create a router for each pair you want to support.
|
||||
|
||||
#### Existing account association
|
||||
|
||||
If a user with the same e-mail address already exists, an HTTP 400 error will be raised by default.
|
||||
|
||||
You can however choose to automatically link this OAuth account to the existing user account by setting the `associate_by_email` flag:
|
||||
|
||||
```py
|
||||
app.include_router(
|
||||
fastapi_users.get_oauth_router(
|
||||
google_oauth_client,
|
||||
auth_backend,
|
||||
"SECRET",
|
||||
associate_by_email=True,
|
||||
),
|
||||
prefix="/auth/google",
|
||||
tags=["auth"],
|
||||
)
|
||||
```
|
||||
|
||||
Bear in mind though that it can lead to security breaches if the OAuth provider does not validate e-mail addresses. How?
|
||||
|
||||
* Let's say your app support an OAuth provider, *Merlinbook*, which does not validate e-mail addresses.
|
||||
* Imagine a user registers to your app with the e-mail address `lancelot@camelot.bt`.
|
||||
* Now, a malicious user creates an account on *Merlinbook* with the same e-mail address. Without e-mail validation, the malicious user can use this account without limitation.
|
||||
* The malicious user authenticates using *Merlinbook* OAuth on your app, which automatically associates to the existing `lancelot@camelot.bt`.
|
||||
* Now, the malicious user has full access to the user account on your app 😞
|
||||
|
||||
#### Association router for authenticated users
|
||||
|
||||
We also provide a router to associate an already authenticated user with an OAuth account. After this association, the user will be able to authenticate with this OAuth provider.
|
||||
|
||||
```py
|
||||
app.include_router(
|
||||
fastapi_users.get_oauth_associate_router(google_oauth_client, UserRead, "SECRET"),
|
||||
prefix="/auth/associate/google",
|
||||
tags=["auth"],
|
||||
)
|
||||
```
|
||||
|
||||
Notice that, just like for the [Users router](./routers/users.md), you have to pass the `UserRead` Pydantic schema.
|
||||
|
||||
### Full example
|
||||
|
||||
!!! warning
|
||||
|
@ -23,6 +23,7 @@ flowchart TB
|
||||
subgraph ROUTERS[Routers]
|
||||
AUTH[[get_auth_router]]
|
||||
OAUTH[[get_oauth_router]]
|
||||
OAUTH_ASSOCIATE[[get_oauth_associate_router]]
|
||||
REGISTER[[get_register_router]]
|
||||
VERIFY[[get_verify_router]]
|
||||
RESET[[get_reset_password_router]]
|
||||
|
@ -214,9 +214,6 @@ Return the authorization URL for the OAuth service where you should redirect you
|
||||
}
|
||||
```
|
||||
|
||||
!!! fail "`422 Validation Error`"
|
||||
Invalid parameters - e.g. unknown authentication backend.
|
||||
|
||||
### `GET /callback`
|
||||
|
||||
Handle the OAuth callback.
|
||||
@ -232,8 +229,8 @@ Depending on the situation, several things can happen:
|
||||
* OAuth account is updated in database with fresh access token.
|
||||
* The user is authenticated following the chosen [authentication method](../configuration/authentication/index.md).
|
||||
* The OAuth account doesn't exist in database but a user with the same email address exists:
|
||||
* OAuth account is linked to the user.
|
||||
* The user is authenticated following the chosen [authentication method](../configuration/authentication/index.md).
|
||||
* By default, an HTTP 400 error is raised.
|
||||
* If [the `associate_by_email` flag is set to `True`](../configuration/oauth.md#existing-account-association) on the router declaration, OAuth account is linked to the user. The user is authenticated following the chosen [authentication method](../configuration/authentication/index.md).
|
||||
* The OAuth account doesn't exist in database and no user with the email address exists:
|
||||
* A new user is created and linked to the OAuth account.
|
||||
* The user is authenticated following the chosen [authentication method](../configuration/authentication/index.md).
|
||||
@ -241,6 +238,15 @@ Depending on the situation, several things can happen:
|
||||
!!! fail "`400 Bad Request`"
|
||||
Invalid token.
|
||||
|
||||
!!! fail "`400 Bad Request`"
|
||||
Another user with the same e-mail address already exists.
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "OAUTH_USER_ALREADY_EXISTS"
|
||||
}
|
||||
```
|
||||
|
||||
!!! fail "`400 Bad Request`"
|
||||
User is inactive.
|
||||
|
||||
@ -250,6 +256,63 @@ Depending on the situation, several things can happen:
|
||||
}
|
||||
```
|
||||
|
||||
## OAuth association router
|
||||
|
||||
Each OAuth association router you define will expose the two following routes.
|
||||
|
||||
### `GET /authorize`
|
||||
|
||||
Return the authorization URL for the OAuth service where you should redirect your user.
|
||||
|
||||
!!! abstract "Query parameters"
|
||||
* `scopes`: Optional list of scopes to ask for. Expected format: `scopes=a&scopes=b`.
|
||||
|
||||
!!! fail "`401 Unauthorized`"
|
||||
Missing token or inactive user.
|
||||
|
||||
!!! success "`200 OK`"
|
||||
```json
|
||||
{
|
||||
"authorization_url": "https://www.tintagel.bt/oauth/authorize?client_id=CLIENT_ID&scopes=a+b&redirect_uri=https://www.camelot.bt/oauth/callback"
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /callback`
|
||||
|
||||
Handle the OAuth callback and add the OAuth account to the current authenticated active user.
|
||||
|
||||
!!! abstract "Query parameters"
|
||||
* `code`: OAuth callback code.
|
||||
* `state`: State token.
|
||||
* `error`: OAuth error.
|
||||
|
||||
!!! fail "`401 Unauthorized`"
|
||||
Missing token or inactive user.
|
||||
|
||||
!!! fail "`400 Bad Request`"
|
||||
Invalid token.
|
||||
|
||||
!!! success "`200 OK`"
|
||||
```json
|
||||
{
|
||||
"id": "57cbb51a-ab71-4009-8802-3f54b4f2e23",
|
||||
"email": "king.arthur@tintagel.bt",
|
||||
"is_active": true,
|
||||
"is_superuser": false,
|
||||
"oauth_accounts": [
|
||||
{
|
||||
"id": "6c98caf5-9bc5-4c4f-8a45-a0ae0c40cd77",
|
||||
"oauth_name": "TINTAGEL",
|
||||
"access_token": "ACCESS_TOKEN",
|
||||
"expires_at": "1641040620",
|
||||
"account_id": "king_arthur_tintagel",
|
||||
"account_email": "king.arthur@tintagel.bt"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Users router
|
||||
|
||||
### `GET /me`
|
||||
|
Reference in New Issue
Block a user