Search code examples
authenticationsecurityoauth-2.0jwtfastapi

FastAPI Docs security example based login


I managed to build a login system with FastAPI using the online documentation security section example. It's more or less the same except you have to get user from MySql. I have two problems. I can only authorize thru FastAPI Docs top right green Authorize button.

API Login function kind of works a valid jwt but...

also gives an error ( handled by API I guess )

(trapped) error reading bcrypt version
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/passlib/handlers/bcrypt.py", line 620, in \_load_backend_mixin
version = \_bcrypt.__about__.__version__
^^^^^^^^^^^^^^^^^
AttributeError: module 'bcrypt' has no attribute '__about__'
INFO:     127.0.0.1:49518 - "POST /login/token HTTP/1.1" 200 OK

And then, when I use this function which depends on jwt...

@router.get("/users/me/", response_model=schemas.User)
async def read_users_me(
current_user: Annotated\[schemas.User, Depends(get_current_active_user)\]
):
return current_user

I get this response from server..

{
"detail": "Not authenticated"
}

However, if I login thru FastAPI/Swagger Docs Authorize then everything works. I checked my token url and seems fine. Any ideas?

I tried to create a login end point from my FastAPI end like explained in this example
However, I could not get it fully working..


Solution

  • If you login through Swagger login button, Swagger will store received token and attach it to every request (in headers).

    But if you login by just using your endpoint (even if you do it through Swagger docs) Swagger will not store your token and attach it to every request. Swagger will just send login request, receive the response and show you this response.

    You can also check it with 'fetch'. Open some url of your API in browser, open developer instruments, console. Call login endpoint and receive token (check login url, username and password)

     fetch(
     'http://127.0.0.1:8000/auth/login',
     {
         method: 'POST',
         credentials: "include",
         headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
         body: "username=EMAIL&password=PWD"
     }
     ).then(resp => resp.text()).then(console.log)
    

    Then try using protected endpoint and send token in headers (substitude TOKEN_RECEIVED_IN_PREVIOUS_STEP with your token)

     fetch(
     'http://127.0.0.1:8000/me',
     {
         method: 'GET',
         credentials: "include",
         headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer TOKEN_RECEIVED_IN_PREVIOUS_STEP' }
     }
     ).then(resp => resp.text()).then(console.log)