-
Notifications
You must be signed in to change notification settings - Fork 185
Feat: bearer token authentication support #591
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
✅ Deploy Preview for poetic-froyo-8baba7 ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
joein
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@skvark thank you for the contribution!
qdrant_client/async_qdrant_remote.py
Outdated
| if self._timeout is not None: | ||
| self._rest_args["timeout"] = self._timeout | ||
| if self._auth_token_provider is not None: | ||
| if self.__class__.__name__ == "QdrantRemote" and asyncio.iscoroutinefunction( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to avoid magic methods checks and avoid adding it to AsyncQdrantClient as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I didn't like this myself either. It's better now after your changes.
qdrant_client/auth/bearer_auth.py
Outdated
| @@ -0,0 +1,44 @@ | |||
| import asyncio | |||
| import threading | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot to clean these after removing some stuff from the auth class.
| self, continuation: Any, client_call_details: Any, request: Any | ||
| ) -> Any: | ||
| new_details, new_request_iterator, postprocess = self._fn( | ||
| new_details, new_request_iterator, postprocess = await self._fn( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch 🙈
qdrant_client/connection.py
Outdated
|
|
||
| def header_adder_interceptor(new_metadata: List[Tuple[str, str]]) -> _GenericClientInterceptor: | ||
| def header_adder_interceptor( | ||
| new_metadata: List[Tuple[str, str]] = [], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lists should not be default values due to their mutability
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True 👍
|
|
||
| ids = [ | ||
| GrpcToRest.convert_point_id(idx) if isinstance(idx, grpc.PointId) else idx | ||
| (GrpcToRest.convert_point_id(idx) if isinstance(idx, grpc.PointId) else idx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it seems like you did not use pre-commit or used a different python version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did use pre-commit but it seems I had too new Python version.
|
I've left some comments, I'll address them and merge |
Thanks for fixing the issues! |
|
Hey @skvark I am somewhat reluctant on bringing new parameters to init (and I think that auth_token_provider actually affects only a small subset of users) Afaik it's not a common practice to propagate token reissue logic into a database object, and it is usually handled on the client side, isn't it? |
Instead of init, we could introduce some new method to the client that registers the authentication token provider. Here's one example from SQLAlchemy. It uses an event-based approach, but the renewal mechanism is the same: https://docs.sqlalchemy.org/en/20/core/engines.html#generating-dynamic-authentication-tokens Weaviate implements the OIDC auth flows themselves (but their DB also validates the tokens so it's a bit different): Weaviate All databases should sit behind a proper authentication (and authorization) layer in addition to firewalls. Oauth 2.0 bearer tokens are the standard way of implementing that layer. We can use the current QDrant client, but not having a proper way to update the authorization headers on the existing Qdrant database client object leads to unnecessarily complicated code on our side. |
|
|
|
I'm going to merge it now, thank you for the contribution @skvark |
Thanks! |
* bearer token authentication provider support * add tests and checks, move auth file to separate dir * fix error message * remove locks * rename var * refactoring: refactor exceptions, fix mypy * fix: regen async * tests: extend token tests to check token updates * new: add warning when auth token provider is used with an insecure connection * fix: propagate auth token to rest client even with prefer_grpc set --------- Co-authored-by: George Panchuk <[email protected]>
All Submissions:
devbranch. Did you create your branch fromdev?New Feature Submissions:
pre-commitwithpip3 install pre-commitand set up hooks withpre-commit install?Changes to Core Features:
What
This pull request adds a custom Bearer authentication token provider function for the HTTP clients. Additionally, Bearer token authentication is enabled for the GRPC clients as well.
Why
Currently, it is impossible to use the clients properly with token-based authentication, since the the only way of passing the token is via the static
metadataparameter. When the token expires, the whole client needs to be recreated.Changes
The clients have a new parameter,
auth_token_provider. This can be sync or async function, that returnsstrBearer token.For the HTTP clients, this PR adds a new custom
BearerAuthclass that is based onhttpx.Authclass (https://www.python-httpx.org/advanced/authentication/#custom-authentication-schemes). This is passed down in theauthparameter to thehttpxlibrary.The GRPC code in
connection.pyhas been refactored to support the new feature and the code inget_channelandget_async_channelshould be simpler now.Example
There are simple examples in the tests, but here is a proper example with
azure-identitylibrary: