Improve extensibility of Transport and Strategy
I want to use FastAPI as a backend for an app that has sign in with google and no other sign in options. I also want to use jwt authentication for each request. Using OAuth2PasswordBearer doesn't work for me - the OpenAPI spec is then generated with a whole user/password flow and requires hitting an endpoint.
The authorize button in swagger shows this whole thing, that I don't need, or want.
I just want to provide a Bearer token and be able to use that for authenticated requests. fastapi-users does let us customize. Lets use fastapi.security.HTTPBearer as the scheme, and build a simple custom transport
# skipping most imports
from fastapi.security import HTTPBearer
class HTTPBearerTransport(Transport):
scheme: HTTPBearer
def __init__(self):
self.scheme = HTTPBearer()
# most everything else the same as OAuth2PasswordBearer
However, this customizability doesn't actually work very well with fastapi-users handling of JWTs.
The scheme/transport returns a HTTPAuthorizationCredentials from fastapi.
But the JWTStrategy in fastapi-users requires a str. There is no way to tell fastapi-users that you need to pull the .credentials property out of the object returned by the transport.
You then need to write a custom JWTStrategy
class HTTPAuthorizationCredentialsJWTStrategy(JWTStrategy):
async def read_token(
self, token: HTTPAuthorizationCredentials | None, user_manager: UserManager
):
token_str = None
if token is not None:
token_str = token.credentials
return await super().read_token(token_str, user_manager)
def get_jwt_strategy() -> JWTStrategy:
return HTTPAuthorizationCredentialsJWTStrategy(
secret=settings.JWT_SECRET,
lifetime_seconds=3600,
token_audience=["fastapi-users:auth"],
)
All of this actually does work - but it is super unergonomic and it means that the extensibility of using a custom transport and strategy is relatively unstable. I was wondering if you might be open to improving the API here such that either the transport or the jwt strategy allows the client to pass in a way to get the underlying token?
Sorry, I guess it isn't a bug and that label is a bit inaccurate.
I have the same problem and I'm new to this, can you help me with some questions? I used your code and seems like it's working, but with additional steps. So I'm wondering how do you get a bearer token itself? Do you go to .../authorize path, get the authorization_url and then go there and authorize with your google account? And after that it redirects you to .../callback path and gives you an access-token, which is the bearer token you need to paste in the form on "Authorize" button? I saw there is OAuth2AuthorizationCodeBearer and if you provide it as a dependency the "Authorize" button will have an option to provide client_id and client_secret and will do google authorization automatically on pressing "Authorize" button in the form. But I think it stores the google token, not the JWT token of the API, so it won't allow you to get access to the protected paths of the API.
So I guess my question is can you make something similar with fastapi-users? So the flow would be pressing the authorize button, it will redirect you to google authorization page and then redirect back to the API and save the JWT token from API to use it to access protected paths?
The generated JWT allows for access to the protected fastapi routes. The Google access token is stored in the db model that the fastapi users library creates. @Chikowitz I am happy to help you out, but this thread might not be the right place for that. Want to DM me on Twitter? Listed in my profile.
Thank you for your interest!
Unfortunately, we're now in maintenance mode, which means we won't add new features and focus only on security and maintenance updates. [Read more]