Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# FastAPI-Login

[![CI](https://img.shields.io/github/actions/workflow/status/MushroomMaula/fastapi_login/python-tests.yml?branch=master)](https://github.com/MushroomMaula/fastapi_login/actions)
[![CI](https://img.shields.io/github/actions/workflow/status/MushroomMaula/fastapi_login/ci.yml)](https://github.com/MushroomMaula/fastapi_login/actions)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/fastapi-login.svg)](https://pypi.org/project/fastapi-login/)
[![PyPI](https://img.shields.io/pypi/v/fastapi-login.svg)](https://pypi.org/project/fastapi-login/)
[![License](https://img.shields.io/github/license/MushroomMaula/fastapi_login.svg)](https://github.com/MushroomMaula/fastapi_login)
Expand Down Expand Up @@ -31,7 +31,7 @@ SECRET = 'your-secret-key'
app = FastAPI()
```

To obtain a suitable secret key you can run `import secrets; secrets.token_hex(24)`.
To obtain a suitable secret key you can run `import secrets; print(secrets.token_hex(24))`.

Now we can import and setup the `LoginManager`, which will handle the process of encoding and decoding our Json Web Tokens.

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**Source Code: [https://github.com/MushroomMaula/fastapi_login](https://github.com/MushroomMaula/fastapi_login)**

fastapi-login provides a convenient, simple to use user authentication for FastAPI.
`fastapi-login` provides a convenient, simple to use user authentication for FastAPI.

## Features

Expand Down
2 changes: 1 addition & 1 deletion docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@
pipenv install fastapi-login
```

Now you can start with the [set up](setup.md).
Now you can start with the [setup](setup.md).
2 changes: 1 addition & 1 deletion docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ normally one would store the secret key in some sort of environment variable.
!!! warning
To obtain a suitable key run the following command in your shell.
```
python -c "import os; print(os.urandom(24).hex())"
python -c "import secrets; print(secrets.token_hex(24))"
```
!!! warning
Most of the time it's better not to store the secret key in a file like this,
Expand Down
1 change: 0 additions & 1 deletion docs_src/advanced_usage/adv_usage_006.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

manager.attach_middleware(app)


@app.route("/showcase")
def showcase(request: Request):
# None if unauthorized
Expand Down
6 changes: 5 additions & 1 deletion docs_src/usage/usage_001.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from fastapi import Depends
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordRequestForm

from fastapi_login.exceptions import InvalidCredentialsException

app = FastAPI()

def query_user(email):
return {"email": email, "password": "password"}

@app.post("/login")
def login(data: OAuth2PasswordRequestForm = Depends()):
Expand Down
2 changes: 1 addition & 1 deletion fastapi_login/fastapi_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def user_loader(self, *args, **kwargs) -> Union[Callable, Callable[..., Awaitabl
>>> from fastapi_login import LoginManager

>>> app = FastAPI()
>>> # use import os; print(os.urandom(24).hex()) to get a suitable secret key
>>> # use import secrets; print(secrets.token_hex(24)) to get a suitable secret key
>>> SECRET = "super-secret"

>>> manager = LoginManager(SECRET, token_url="Login")
Expand Down
165 changes: 46 additions & 119 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pymdown-extensions = "*"
ruff = "^0.8.2"

[tool.poetry.group.test.dependencies]
async-asgi-testclient = "*"
httpx = "^0.28.1"
pytest = ">=8"
pytest-asyncio = "*"
pytest-lazy-fixtures = "^1.1.1"
Expand All @@ -66,4 +66,4 @@ requires = ["poetry-core>=1.0.0"]

[tool.pytest.ini_options]
addopts = "--ignore=examples"
asyncio_default_fixture_loop_scope = "function"
asyncio_default_fixture_loop_scope = "session"
12 changes: 8 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from typing import Callable, Dict

import pytest
from async_asgi_testclient import TestClient
from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
from pydantic import BaseModel

from fastapi_login import LoginManager
Expand Down Expand Up @@ -33,7 +33,7 @@ def generate_rsa_key(key_size=2048, password=None):
except ImportError:
_has_cryptography = False

def generate_rsa_key(*args, **kwargs):
def generate_rsa_key(key_size=2048, password=None):
return b""


Expand Down Expand Up @@ -108,8 +108,12 @@ def token_url() -> str:


@pytest.fixture(scope="module")
def client(app) -> TestClient:
return TestClient(app)
def client(app):
return AsyncClient(
transport=ASGITransport(app=app),
base_url="http://test",
follow_redirects=True,
)


@pytest.fixture()
Expand Down
1 change: 0 additions & 1 deletion tests/test_advanced/test_exception_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ async def test_exception_handling(exception_manager, client, invalid_data):
resp = await client.get(
"/private/exception", headers={"Authorization": f"Bearer {invalid_token}"}
)

assert resp.json()["detail"] == "Redirected"


Expand Down
11 changes: 6 additions & 5 deletions tests/test_dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ async def test_header_dependency(client, header_manager, default_data):
@pytest.mark.asyncio
async def test_cookie_dependency(client, cookie_manager, default_data):
token = cookie_manager.create_access_token(data=default_data)
resp = await client.get(
"/private/cookie", cookies={cookie_manager.cookie_name: token}
)
client._cookies = client._merge_cookies({cookie_manager.cookie_name: token})
resp = await client.get("/private/cookie")
client._cookies.clear()

assert resp.status_code == 200
assert resp.json()["detail"] == "Success"
Expand All @@ -87,8 +87,9 @@ async def test_cookie_dependency(client, cookie_manager, default_data):
@pytest.mark.asyncio
async def test_cookie_header_fallback(client, cookie_header_manager, default_data):
token = cookie_header_manager.create_access_token(data=default_data)
client._cookies.clear()
resp = await client.get(
"/private/both", headers={"Authorization": f"Bearer {token}"}, cookies={}
"/private/both", headers={"Authorization": f"Bearer {token}"}
)

# even tough no valid access cookie is present,
Expand Down Expand Up @@ -127,7 +128,7 @@ async def test_optional_dependency(client, cookie_header_manager, data, is_inval
resp = await client.get(
"/private/optional",
headers={"Authorization": f"Bearer {token}"},
query_string={"invalid": is_invalid},
params={"invalid": is_invalid},
)

assert resp.status_code == 200
Expand Down
Loading