Skip to content
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

Get Token #71

Closed
Vad1mo opened this issue Apr 25, 2021 · 3 comments
Closed

Get Token #71

Vad1mo opened this issue Apr 25, 2021 · 3 comments

Comments

@Vad1mo
Copy link

Vad1mo commented Apr 25, 2021

In order to call an API with the bearer token, I need to get an /oauth/token first.
What is your suggestion on how to accomplish this with api-client?

specifically in context that the /oauth/token might expire and need to be renewed once the API server returns a 401.

@mom1
Copy link
Contributor

mom1 commented Apr 27, 2021

Maybe Retrying help you.

@MikeWooster
Copy link
Owner

I don't think the client is yet capable of doing this. But not a bad idea for a new version. But in the meantime, I'd recommend maybe looking into retrying, but I'm not sure if that will have enough knowledge of the client implementation itself. Potentially you could extend the HeaderAuthentication so that it works out if the token is invalid or has expired and requests a new one? If you couple that with retrying on 401s, you might have a working solution.

@mom1
Copy link
Contributor

mom1 commented Aug 30, 2021

This is most likely not the best solution, but still I'll leave it here:

# endpoints.py
from apiclient import endpoint


@endpoint(base_url='https://base.com')
class Endpoints:
    oauth_token = '/oauth/token'
    some1 = 'some1'
    some2 = 'some2'


# authentication_methods.py
from .endpoints import Endpoints


class HeaderAuthenticationRetry(HeaderAuthentication):
    def __init__(self, token: Optional[str] = None, **kwargs):
        super().__init__(token or '', **kwargs)

    def perform_initial_auth(self, client: APIClient, force: bool= Fasle):
        if force:
            self._token = client.get_token()
            # or
            self._token = client.get(Endpoints.oauth_token)

    def get_headers(self) -> Dict[str, str]:
        if self._token:
            return super().get_headers()
        return {}

# retrying.py
from apiclient.retrying import retry_if_api_request_error
from tenacity import RetryCallState, retry, stop_after_attempt, wait_fixed

from .authentication_methods import HeaderAuthenticationRetry


class retry_auth(retry_if_api_request_error):  # noqa: N801
    def __call__(self, retry_state: RetryCallState) -> bool:
        ret = super().__call__(retry_state=retry_state)
        if ret:
            client, *_ = retry_state.args
            auth = client.get_authentication_method()
            if isinstance(auth, HeaderAuthenticationRetry):
                auth._token = None
                auth.perform_initial_auth(client, force=True)
        return ret


use_token = retry(retry=retry_auth(status_codes=[401]), wait=wait_fixed(1), stop=stop_after_attempt(2), reraise=True)


# client.py
from .retrying import use_token
from .endpoints import Endpoints


class MyAPIClient(APIClient):
    def __init__(
        self,
        authentication_method: Optional[BaseAuthenticationMethod] = None,
        **kwargs,
    ):
        super().__init__(
            authentication_method=authentication_method or HeaderAuthenticationRetry(),
            **kwargs,
        )

    # Not auth
    def get_some1(self):
        return self.get(Endpoints.some1)

    # Auth
    @use_token
    def get_some2(self):
        return self.get(Endpoints.some2)
#  Use
client = MyAPIClient()
client.get_some1()  #  1 request without token
client.get_some2()  #  3 requests 1 - without token (401), 1 - get token, 1 - with token in header
client.get_some1()  #  1 request with token. Because it was saved in the previous request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants