Skip to content

Commit

Permalink
📝 Update docs for handling HTTP Basic Auth with `secrets.compare_dige…
Browse files Browse the repository at this point in the history
…st()` to account for non-ASCII characters (#3536)

Co-authored-by: le_woudar <kevin.tewouda@gandi.net>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
  • Loading branch information
3 people committed Aug 24, 2022
1 parent f90465f commit 8c6ad35
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 7 deletions.
14 changes: 10 additions & 4 deletions docs/en/docs/advanced/security/http-basic-auth.md
Expand Up @@ -34,13 +34,19 @@ Here's a more complete example.

Use a dependency to check if the username and password are correct.

For this, use the Python standard module <a href="https://docs.python.org/3/library/secrets.html" class="external-link" target="_blank">`secrets`</a> to check the username and password:
For this, use the Python standard module <a href="https://docs.python.org/3/library/secrets.html" class="external-link" target="_blank">`secrets`</a> to check the username and password.

```Python hl_lines="1 11-13"
`secrets.compare_digest()` needs to take `bytes` or a `str` that only contains ASCII characters (the ones in English), this means it wouldn't work with characters like `á`, as in `Sebastián`.

To handle that, we first convert the `username` and `password` to `bytes` encoding them with UTF-8.

Then we can use `secrets.compare_digest()` to ensure that `credentials.username` is `"stanleyjobson"`, and that `credentials.password` is `"swordfish"`.

```Python hl_lines="1 11-21"
{!../../../docs_src/security/tutorial007.py!}
```

This will ensure that `credentials.username` is `"stanleyjobson"`, and that `credentials.password` is `"swordfish"`. This would be similar to:
This would be similar to:

```Python
if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
Expand Down Expand Up @@ -102,6 +108,6 @@ That way, using `secrets.compare_digest()` in your application code, it will be

After detecting that the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again:

```Python hl_lines="15-19"
```Python hl_lines="23-27"
{!../../../docs_src/security/tutorial007.py!}
```
14 changes: 11 additions & 3 deletions docs_src/security/tutorial007.py
Expand Up @@ -9,9 +9,17 @@


def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
correct_username = secrets.compare_digest(credentials.username, "stanleyjobson")
correct_password = secrets.compare_digest(credentials.password, "swordfish")
if not (correct_username and correct_password):
current_username_bytes = credentials.username.encode("utf8")
correct_username_bytes = b"stanleyjobson"
is_correct_username = secrets.compare_digest(
current_username_bytes, correct_username_bytes
)
current_password_bytes = credentials.password.encode("utf8")
correct_password_bytes = b"swordfish"
is_correct_password = secrets.compare_digest(
current_password_bytes, correct_password_bytes
)
if not (is_correct_username and is_correct_password):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
Expand Down

0 comments on commit 8c6ad35

Please sign in to comment.