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

Possible to auto refresh client_credentials access token? #260

Open
jaddison opened this issue Jan 17, 2017 · 5 comments
Open

Possible to auto refresh client_credentials access token? #260

jaddison opened this issue Jan 17, 2017 · 5 comments

Comments

@jaddison
Copy link

As a client_credentials based access token has no refresh token, the refresh_token() functionality raises an exception (ie. InvalidRequestError: Missing refresh token parameter.). Based on the spec, I believe this is technically fine - one should fetch a new access token in this case.

Is it just the spec that prevents requests-oauthlib from handling this scenario gracefully alongside the current token expiration code handling in the request() method on OAuth2Session?

If I subclass OAuth2Session like so:

class RefreshOAuth2Session(OAuth2Session):
    def request(self, *args, **kwargs):
        try:
            return super().request(*args, **kwargs)
        except TokenExpiredError:
            self.token = self.fetch_token(
                token_url=OAUTH2_TOKEN_URL,
                **self.auto_refresh_kwargs
            )
            self.token_updater(self.token)
            return super().request(*args, **kwargs)

I can use it like this:

class MyClass(object):
    _session = None
    _token = None

    def token_updater(self, token):
        self._token = token

    @property
    def session(self):
        if self._session is None:
            self._session = RefreshOAuth2Session(
                client=BackendApplicationClient(client_id=self.client_id),
                token=self.token,
                token_updater=self.token_updater,
                auto_refresh_kwargs={
                    'client_id': self.client_id,
                    'client_secret': self.client_secret,
                }
            )
        return self._session

    @property
    def token(self):
        if self._token is None:
            self._token = RefreshOAuth2Session(
                client=BackendApplicationClient(client_id=self.client_id)
            ).fetch_token(
                token_url=OAUTH2_TOKEN_URL,
                client_id=self.client_id,
                client_secret=self.client_secret
            )
        return self._token

    def __init__(self, *args, **kwargs):
        super(MyClass, self).__init__(*args, **kwargs)
        self.client_id = CLIENT_ID
        self.client_secret = CLIENT_SECRET

    def get_information(self):
        return self.session.get('https://localhost:10000/api/infomation/')


obj = MyClass()
obj.get_information()

As long as auto_refresh_url is not passed in, the logic in my subclass handles everything smoothly. Could logic be added to request() to cover this scenario, rather than having to kludge this as I've done?

Related thread: https://groups.google.com/d/msg/django-oauth-toolkit/iSIiZQtn0mM/5SDckbyTCQAJ

@Lukasa
Copy link
Member

Lukasa commented Jan 17, 2017

I don't see any problem with adding some logic to request() to cover this scenario.

@btimby
Copy link

btimby commented Mar 3, 2017

I am having similar issues.

#264

@IvanAnishchuk
Copy link

I solved this issue by subclassing oauthlib's BackendApplicationClient and adding

    def prepare_refresh_body(self, body='', refresh_token=None, scope=None, **kwargs):
        return self.prepare_request_body(boby=body, scope=scope, **kwargs)

Then you can pass such a client to Oauth2Session as normal.

But, indeed, a solution that doesn't require custom code would be most welcome.

@denizdogan
Copy link

Is anyone working on a solution to this? The suggestion from @IvanAnishchuk doesn't seem to do the trick for me. The only way I manage to make it work is by catching TokenExpired and manually fetch a token from there.

It looks to me like there's some non-trivial refactoring that is required to make this work well. OAuth2Session works under the assumption that there is such a thing as a refresh token, but it's normally not the case for the client_credentials flow.

It's not clear to me exactly where the line is drawn between the Client and the Session and what the responsibility of each is. It also doesn't make sense to me that client ID is a required parameter for BackendApplicationClient, since, as I understand the client_credentials flow, it's only used (in combination with the client secret) for getting an access token and nothing else.

Could someone help me out here? Is the client_credentials really still not fully supported? Is there anything we can do to make it happen?

@singingwolfboy
Copy link
Member

Is anyone working on a solution to this?

Unfortunately, probably not. See #385 for more context.

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

Successfully merging a pull request may close this issue.

6 participants