authx icon indicating copy to clipboard operation
authx copied to clipboard

Example from documentation doesn't work

Open John2013 opened this issue 1 year ago • 3 comments

I tried to run the example from https://authx.yezz.me/get-started/basic-usage/ and got an error:

INFO:     127.0.0.1:18932 - "GET /login?username=test&password=test HTTP/1.1" 200 OK
INFO:     127.0.0.1:18980 - "GET /protected HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\uvicorn\protocols\http\httptools_impl.py", line 409, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 60, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\fastapi\applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\applications.py", line 113, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\middleware\errors.py", line 187, in __call__
    raise exc
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\middleware\errors.py", line 165, in __call__
    await self.app(scope, receive, _send)
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 62, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\routing.py", line 715, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\routing.py", line 735, in app
    await route.handle(scope, receive, send)
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\routing.py", line 288, in handle
    await self.app(scope, receive, send)
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\routing.py", line 76, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\starlette\routing.py", line 73, in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\fastapi\routing.py", line 291, in app
    solved_result = await solve_dependencies(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\fastapi\dependencies\utils.py", line 638, in solve_dependencies
    solved = await call(**solved_result.values)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\authx\main.py", line 619, in _auth_required
    return await self._auth_required(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\authx\main.py", line 351, in _auth_required
    request_token = await method(
                    ^^^^^^^^^^^^^
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\authx\main.py", line 308, in get_access_token_from_request
    return await self._get_token_from_request(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\authx\main.py", line 281, in _get_token_from_request
    return await _get_token_from_request(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\nawas\PycharmProjects\fastapi_playground\.venv\Lib\site-packages\authx\core.py", line 156, in _get_token_from_request
    raise MissingTokenError(*(str(err) for err in errors))
authx.exceptions.MissingTokenError: Missing 'Bearer' in 'Authorization' header.

John2013 avatar Dec 13 '24 13:12 John2013

I believe your second request is just curl -s http://0.0.0.0:8000/protected . You used this because it is under the Protected Routes - curl-without-jsonwebtoken section.

The error is on purpose, as it demonstrates an unauthorized request to a protected endpoint. If you want to see response to an authorized request, you should use the example under the tab "With a valid JsonWebToken".

This behaviour is actually explained under that very section:

In the curl requests above, a 401 HTTP Error is raised when the token is not valid. By default, AuthX triggers a 500 Internal Server Error HTTP Error. For the sake of simplicity, we won't delve into error handling in this section.

Example of a valid request (access token will be different in your case):

curl -s --oauth2-bearer eyJhbGciOiJIUzI1NiIsInR5cCI6...9vJcIWEE http://127.0.0.1:8000/protected

(I just tried it in local just to be sure that it still works. response: {"message":"Hello World"} )

Edit: I wanted to add that maybe you are looking for handling these exceptions automatically, in which case you should use auth.handle_errors(app) and (optionally) try&except as you can see here.

gokhanmeteerturk avatar Dec 13 '24 16:12 gokhanmeteerturk

Hello @John2013 Yes I'm working on a big refactoring for the documentation!

cc @gokhanmeteerturk in case you want to open a Pull request to fix the issue 🚀

yezz123 avatar Dec 25 '24 22:12 yezz123

Hello, most of the examples in the documentation don't seem to work. For instance, the TokenPayload example from https://authx-git-docs-fix-yasser-tahiris-projects.vercel.app/get-started/payload/ doesn't function as expected.

Versions

Platform: Windows 11
Python: 3.13.2

fastapi: 0.115.14
authx: 1.4.3

Code

import requests
import uvicorn

from fastapi import FastAPI, Depends, HTTPException
from authx import AuthX, AuthXConfig, RequestToken, TokenPayload

app = FastAPI()

config = AuthXConfig(
    JWT_ALGORITHM="HS256",
    JWT_SECRET_KEY="4AA743755308486A17A322F93A59598C",
    JWT_TOKEN_LOCATION=["headers"],
)

auth = AuthX(config=config)
auth.handle_errors(app)


@app.get('/token')
def get_token():
    token = auth.create_access_token(uid="123", foo="bar", age=22)
    return {"access_token": token}


@app.get('/profile')
def get_profile(payload: TokenPayload = Depends(auth.access_token_required)):
    return {
        "id": payload.sub,
        "age": getattr(payload, "age"),
        "foo": getattr(payload, "foo"),
    }

@app.get("/protected")
def get_protected(token: RequestToken = Depends(auth.access_token_required)):
    try:
        # auth.verify_token(token=token)
        return {"message": f"Hello world! {token.sub}"}
    except Exception as e:
        raise HTTPException(401, detail={"message": str(e)}) from e


def test_request():
    response = requests.get("http://127.0.0.1:8000/token")
    access_token = response.json().get("access_token")
    print(access_token)

    response = requests.get("http://127.0.0.1:8000/protected",
                            headers={"Authorization": f"Bearer {access_token}"})
    print(response.json()) if response.status_code == 200 else print(response.text)

    response = requests.get("http://127.0.0.1:8000/profile",
                            headers={"Authorization": f"Bearer {access_token}"})
    print(response.json()) if response.status_code == 200 else print(response.status_code)


def main():
    uvicorn.run(app, host="127.0.0.1", port=8000)


if __name__ == '__main__':
    main()

Request

>>> from testtest import test_request2
>>> test_request2()
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJqdGkiOiI3Y2JkOTE5MS1hNTNkLTQ0NmUtODJkNy1iNDZhYThjNjY5OTAiLCJ0eXBlIjoiYWNjZXNzIiwiZnJlc2giOmZhbHNlLCJjc3JmIjoiIiwiaWF0IjoxNzU4MzU2NTE3LCJleHAiOjE3NTgzNTc0MTcuODY3ODF9.P0wNvgc8M6X-v6Qb4gmesTHqKMDqVztSJ0jvAdTUbAE
{'message': 'Hello world! 123'}
500

JWTDecode

{
  "sub": "123",
  "jti": "7cbd9191-a53d-446e-82d7-b46aa8c66990",
  "type": "access",
  "fresh": false,
  "csrf": "",
  "iat": 1758356517,
  "exp": 1758357417.86781
}

Traceback

Traceback (most recent call last):
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 403, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        self.scope, self.receive, self.send
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 60, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\fastapi\applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\middleware\errors.py", line 187, in __call__
    raise exc
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\middleware\errors.py", line 165, in __call__
    await self.app(scope, receive, _send)
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\middleware\exceptions.py", line 62, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\routing.py", line 714, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\routing.py", line 734, in app
    await route.handle(scope, receive, send)
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\routing.py", line 288, in handle
    await self.app(scope, receive, send)
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\routing.py", line 76, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\routing.py", line 73, in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\fastapi\routing.py", line 301, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<3 lines>...
    )
    ^
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\fastapi\routing.py", line 214, in run_endpoint_function
    return await run_in_threadpool(dependant.call, **values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\starlette\concurrency.py", line 37, in run_in_threadpool
    return await anyio.to_thread.run_sync(func)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\anyio\to_thread.py", line 56, in run_sync
    return await get_async_backend().run_sync_in_worker_thread(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        func, args, abandon_on_cancel=abandon_on_cancel, limiter=limiter
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\anyio\_backends\_asyncio.py", line 2476, in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\anyio\_backends\_asyncio.py", line 967, in run
    result = context.run(func, *args)
  File "H:\WoLSite\testtest.py", line 29, in get_profile
    "age": getattr(payload, "age"),
           ~~~~~~~^^^^^^^^^^^^^^^^
  File "C:\Users\ibras\AppData\Local\pypoetry\Cache\virtualenvs\wol-api-4qW3MH0p-py3.13\Lib\site-packages\pydantic\main.py", line 991, in __getattr__
    raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')
AttributeError: 'TokenPayload' object has no attribute 'age'

Cybernoobi avatar Sep 20 '25 08:09 Cybernoobi