box / box-python-sdk

Box SDK for Python
http://opensource.box.com/box-python-sdk/
Apache License 2.0
417 stars 214 forks source link

How to set a downscoped token #813

Closed tehunter closed 1 year ago

tehunter commented 1 year ago

Hi, I'm building an library to interface boxsdk with Python's fsspec library. I want to give users the ability to set downscoped permissions. I'm struggling with how to actually make use of a downscoped TokenResponse using public functions.

Here's an overview of how the interface would work.

class BoxFileSystem(fsspec.AbstractFileSystem):
    def __init__(self, client=None, auth=None, scopes=[], item=None, ...):
        """User passes instantiated client
        if client:
            self.client=client
        else:
            self.client=Client(auth)

        token_info = self.client.downscope_token(scopes, item)
        # What to do next? e.g.
        # self.client.clone().set_token(token_info.access_token)

As far as I can tell, there's no way to actually apply token_info.access_token to update the Client to use the downscoped token. All of the functions in OAuth2 for setting tokens are "private", so I don't want to use them in case the signatures change in the future. Similarly, creating a new OAuth object would require accessing client.auth._client_secret which is also protected. If I try self.client.auth.access_token = token_info.access_token, I get AttributeError: can't set attribute 'access_token' since it is being accessed as a @property without a setter.

So my questions are:

  1. Is there a process for getting a downscoped token and using it in boxsdk using only publicly accessible functions?
    1. If so, I'd recommend documentation be updated to provide an example of this. The current documentation only gets a downscoped token and prints it from the response object, but never uses the token.
    2. If not, I would like to propose it for a future change.

It looks like the Java SDK offers a method to set the access token value, so that seems like the best solution here to make the SDK's compatible.

antusus commented 1 year ago

Hello @tehunter ,

the best way to do that is to use same approach as using developer token:

token_info = client.downscope_token([TokenScope.ITEM_READ, TokenScope.ITEM_PREVIEW])
downscoped_client = Client(
    OAuth2(
    client_id=None,
    client_secret=None,
    access_token=token_info.access_token
    )
)

You can look at DeveloperTokenAuth here.

As with developer token there is no refresh mechanism so you will need to catch those 401 errors and rebuild the client with new down scoped token.

tehunter commented 1 year ago

Thanks, that approach worked!