* 🍱 Add new source examples with Annotated for Query Params and String Validations * 📝 Add new docs with Annotated for Query Params and String Validations * 🚚 Rename incorrectly named tests for Query Params and str validations * ✅ Add new tests with Annotated for Query Params and Sring Validations examples * 🍱 Add new examples with Annotated for Intro to Python Types * 📝 Update Python Types Intro, include Annotated * 🎨 Fix formatting in Query params and string validation, and highlight * 🍱 Add new Annotated source examples for Path Params and Numeric Validations * 📝 Update docs for Path Params and Numeric Validations with Annotated * 🍱 Add new source examples with Annotated for Body - Multiple Params * 📝 Update docs with Annotated for Body - Multiple Parameters * ✅ Add test for new Annotated examples in Body - Multiple Parameters * 🍱 Add new Annotated source examples for Body Fields * 📝 Update docs for Body Fields with new Annotated examples * ✅ Add new tests for new Annotated examples for Body Fields * 🍱 Add new Annotated source examples for Schema Extra (Example Data) * 📝 Update docs for Schema Extra with Annotated * ✅ Add tests for new Annotated examples for Schema Extra * 🍱 Add new Annnotated source examples for Extra Data Types * 📝 Update docs with Annotated for Extra Data Types * ✅ Add tests for new Annotated examples for Extra Data Types * 🍱 Add new Annotated source examples for Cookie Parameters * 📝 Update docs for Cookie Parameters with Annotated examples * ✅ Add tests for new Annotated source examples in Cookie Parameters * 🍱 Add new Annotated examples for Header Params * 📝 Update docs with Annotated examples for Header Parameters * ✅ Add tests for new Annotated examples for Header Params * 🍱 Add new Annotated examples for Form Data * 📝 Update Annotated docs for Form Data * ✅ Add tests for new Annotated examples in Form Data * 🍱 Add new Annotated source examples for Request Files * 📝 Update Annotated docs for Request Files * ✅ Test new Annotated examples for Request Files * 🍱 Add new Annotated source examples for Request Forms and Files * ✅ Add tests for new Anotated examples for Request Forms and Files * 🍱 Add new Annotated source examples for Dependencies and Advanced Dependencies * ✅ Add tests for new Annotated dependencies * 📝 Add new docs for using Annotated with dependencies including type aliases * 📝 Update docs for Classes as Dependencies with Annotated * 📝 Update docs for Sub-dependencies with Annotated * 📝 Update docs for Dependencies in path operation decorators with Annotated * 📝 Update docs for Global Dependencies with Annotated * 📝 Update docs for Dependencies with yield with Annotated * 🎨 Update format in example for dependencies with Annotated * 🍱 Add source examples with Annotated for Security * ✅ Add tests for new Annotated examples for security * 📝 Update docs for Security - First Steps with Annotated * 📝 Update docs for Security: Get Current User with Annotated * 📝 Update docs for Simple OAuth2 with Password and Bearer with Annotated * 📝 Update docs for OAuth2 with Password (and hashing), Bearer with JWT tokens with Annotated * 📝 Update docs for Request Forms and Files with Annotated * 🍱 Add new source examples for Bigger Applications with Annotated * ✅ Add new tests for Bigger Applications with Annotated * 📝 Update docs for Bigger Applications - Multiple Files with Annotated * 🍱 Add source examples for background tasks with Annotated * 📝 Update docs for Background Tasks with Annotated * ✅ Add test for Background Tasks with Anotated * 🍱 Add new source examples for docs for Testing with Annotated * 📝 Update docs for Testing with Annotated * ✅ Add tests for Annotated examples for Testing * 🍱 Add new source examples for Additional Status Codes with Annotated * ✅ Add tests for new Annotated examples for Additional Status Codes * 📝 Update docs for Additional Status Codes with Annotated * 📝 Update docs for Advanced Dependencies with Annotated * 📝 Update docs for OAuth2 scopes with Annotated * 📝 Update docs for HTTP Basic Auth with Annotated * 🍱 Add source examples with Annotated for WebSockets * ✅ Add tests for new Annotated examples for WebSockets * 📝 Update docs for WebSockets with new Annotated examples * 🍱 Add source examples with Annotated for Settings and Environment Variables * 📝 Update docs for Settings and Environment Variables with Annotated * 🍱 Add new source examples for testing dependencies with Annotated * ✅ Add tests for new examples for testing dependencies * 📝 Update docs for testing dependencies with new Annotated examples * ✅ Update and fix marker for Python 3.9 test * 🔧 Update Ruff ignores for source examples in docs * ✅ Fix some tests in the grid for Python 3.9 (incorrectly testing 3.10) * 🔥 Remove source examples and tests for (non existent) docs section about Annotated, as it's covered in all the rest of the docs
9.0 KiB
Security - First Steps
Let's imagine that you have your backend API in some domain.
And you have a frontend in another domain or in a different path of the same domain (or in a mobile application).
And you want to have a way for the frontend to authenticate with the backend, using a username and password.
We can use OAuth2 to build that with FastAPI.
But let's save you the time of reading the full long specification just to find those little pieces of information you need.
Let's use the tools provided by FastAPI to handle security.
How it looks
Let's first just use the code and see how it works, and then we'll come back to understand what's happening.
Create main.py
Copy the example in a file main.py:
=== "Python 3.6 and above"
```Python
{!> ../../../docs_src/security/tutorial001_an.py!}
```
=== "Python 3.9 and above"
```Python
{!> ../../../docs_src/security/tutorial001_an_py39.py!}
```
=== "Python 3.6 and above - non-Annotated"
!!! tip
Try to use the main, `Annotated` version better.
```Python
{!> ../../../docs_src/security/tutorial001.py!}
```
Run it
!!! info
First install python-multipart.
E.g. `pip install python-multipart`.
This is because **OAuth2** uses "form data" for sending the `username` and `password`.
Run the example with:
$ uvicorn main:app --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Check it
Go to the interactive docs at: http://127.0.0.1:8000/docs.
You will see something like this:
!!! check "Authorize button!" You already have a shiny new "Authorize" button.
And your *path operation* has a little lock in the top-right corner that you can click.
And if you click it, you have a little authorization form to type a username and password (and other optional fields):
!!! note It doesn't matter what you type in the form, it won't work yet. But we'll get there.
This is of course not the frontend for the final users, but it's a great automatic tool to document interactively all your API.
It can be used by the frontend team (that can also be yourself).
It can be used by third party applications and systems.
And it can also be used by yourself, to debug, check and test the same application.
The password flow
Now let's go back a bit and understand what is all that.
The password "flow" is one of the ways ("flows") defined in OAuth2, to handle security and authentication.
OAuth2 was designed so that the backend or API could be independent of the server that authenticates the user.
But in this case, the same FastAPI application will handle the API and the authentication.
So, let's review it from that simplified point of view:
- The user types the
usernameandpasswordin the frontend, and hitsEnter. - The frontend (running in the user's browser) sends that
usernameandpasswordto a specific URL in our API (declared withtokenUrl="token"). - The API checks that
usernameandpassword, and responds with a "token" (we haven't implemented any of this yet).- A "token" is just a string with some content that we can use later to verify this user.
- Normally, a token is set to expire after some time.
- So, the user will have to log in again at some point later.
- And if the token is stolen, the risk is less. It is not like a permanent key that will work forever (in most of the cases).
- The frontend stores that token temporarily somewhere.
- The user clicks in the frontend to go to another section of the frontend web app.
- The frontend needs to fetch some more data from the API.
- But it needs authentication for that specific endpoint.
- So, to authenticate with our API, it sends a header
Authorizationwith a value ofBearerplus the token. - If the token contains
foobar, the content of theAuthorizationheader would be:Bearer foobar.
FastAPI's OAuth2PasswordBearer
FastAPI provides several tools, at different levels of abstraction, to implement these security features.
In this example we are going to use OAuth2, with the Password flow, using a Bearer token. We do that using the OAuth2PasswordBearer class.
!!! info A "bearer" token is not the only option.
But it's the best one for our use case.
And it might be the best for most use cases, unless you are an OAuth2 expert and know exactly why there's another option that suits better your needs.
In that case, **FastAPI** also provides you with the tools to build it.
When we create an instance of the OAuth2PasswordBearer class we pass in the tokenUrl parameter. This parameter contains the URL that the client (the frontend running in the user's browser) will use to send the username and password in order to get a token.
=== "Python 3.6 and above"
```Python hl_lines="7"
{!> ../../../docs_src/security/tutorial001_an.py!}
```
=== "Python 3.9 and above"
```Python hl_lines="8"
{!> ../../../docs_src/security/tutorial001_an_py39.py!}
```
=== "Python 3.6 and above - non-Annotated"
!!! tip
Try to use the main, `Annotated` version better.
```Python hl_lines="6"
{!> ../../../docs_src/security/tutorial001.py!}
```
!!! tip
Here tokenUrl="token" refers to a relative URL token that we haven't created yet. As it's a relative URL, it's equivalent to ./token.
Because we are using a relative URL, if your API was located at `https://example.com/`, then it would refer to `https://example.com/token`. But if your API was located at `https://example.com/api/v1/`, then it would refer to `https://example.com/api/v1/token`.
Using a relative URL is important to make sure your application keeps working even in an advanced use case like [Behind a Proxy](../../advanced/behind-a-proxy.md){.internal-link target=_blank}.
This parameter doesn't create that endpoint / path operation, but declares that the URL /token will be the one that the client should use to get the token. That information is used in OpenAPI, and then in the interactive API documentation systems.
We will soon also create the actual path operation.
!!! info
If you are a very strict "Pythonista" you might dislike the style of the parameter name tokenUrl instead of token_url.
That's because it is using the same name as in the OpenAPI spec. So that if you need to investigate more about any of these security schemes you can just copy and paste it to find more information about it.
The oauth2_scheme variable is an instance of OAuth2PasswordBearer, but it is also a "callable".
It could be called as:
oauth2_scheme(some, parameters)
So, it can be used with Depends.
Use it
Now you can pass that oauth2_scheme in a dependency with Depends.
=== "Python 3.6 and above"
```Python hl_lines="11"
{!> ../../../docs_src/security/tutorial001_an.py!}
```
=== "Python 3.9 and above"
```Python hl_lines="12"
{!> ../../../docs_src/security/tutorial001_an_py39.py!}
```
=== "Python 3.6 and above - non-Annotated"
!!! tip
Try to use the main, `Annotated` version better.
```Python hl_lines="10"
{!> ../../../docs_src/security/tutorial001.py!}
```
This dependency will provide a str that is assigned to the parameter token of the path operation function.
FastAPI will know that it can use this dependency to define a "security scheme" in the OpenAPI schema (and the automatic API docs).
!!! info "Technical Details"
FastAPI will know that it can use the class OAuth2PasswordBearer (declared in a dependency) to define the security scheme in OpenAPI because it inherits from fastapi.security.oauth2.OAuth2, which in turn inherits from fastapi.security.base.SecurityBase.
All the security utilities that integrate with OpenAPI (and the automatic API docs) inherit from `SecurityBase`, that's how **FastAPI** can know how to integrate them in OpenAPI.
What it does
It will go and look in the request for that Authorization header, check if the value is Bearer plus some token, and will return the token as a str.
If it doesn't see an Authorization header, or the value doesn't have a Bearer token, it will respond with a 401 status code error (UNAUTHORIZED) directly.
You don't even have to check if the token exists to return an error. You can be sure that if your function is executed, it will have a str in that token.
You can try it already in the interactive docs:
We are not verifying the validity of the token yet, but that's a start already.
Recap
So, in just 3 or 4 extra lines, you already have some primitive form of security.