Skip to content

Latest commit

 

History

History
417 lines (329 loc) · 16.7 KB

authentication.md

File metadata and controls

417 lines (329 loc) · 16.7 KB

Authentication

The Box API uses OAuth2 for authentication, which can be difficult to implement. The SDK makes it easier by providing classes that handle obtaining tokens and automatically refreshing them when possible. See the OAuth 2 overview for a detailed overview of how the Box API handles authentication.

Ways to Authenticate

Developer Token

The fastest way to get started using the API is with developer tokens. A developer token is simply a short-lived access token that cannot be refreshed and can only be used with your own account. Therefore, they're only useful for testing an app and aren't suitable for production. You can obtain a developer token from your application's developer console page.

For manual testing in a Python REPL, you can interactively create a DevelopmentClient. This client will prompt for a new developer token any time the current one expires, and will automatically log API requests and responses for testing and debugging.

>>> from boxsdk import DevelopmentClient
>>> client = DevelopmentClient()
Enter developer token: <ENTER DEVELOPER TOKEN HERE>
>>> me = client.user().get()
GET https://api.box.com/2.0/users/me {'headers': {'Authorization': '---wXyZ',
             'User-Agent': 'box-python-sdk-2.0.0',
             'X-Box-UA': 'agent=box-python-sdk/2.0.0; env=python/3.6.5'},
 'params': None}
"GET https://api.box.com/2.0/users/me" 200 454
{'Date': 'Tue, 30 Oct 2018 20:57:36 GMT', 'Content-Type': 'application/json', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Strict-Transport-Security': 'max-age=31536000', 'Cache-Control': 'no-cache, no-store', 'Content-Encoding': 'gzip', 'Vary': 'Accept-Encoding', 'BOX-REQUEST-ID': '0dnjcjpu1krfunto6s7mrpal2ba', 'Age': '0'}
{'address': '',
 'avatar_url': 'https://cloud.app.box.com/api/avatar/large/33333',
 'created_at': '2012-06-07T11:14:50-07:00',
 'id': '33333',
 'job_title': '',
 'language': 'en',
 'login': '[email protected]',
 'max_upload_size': 16106127360,
 'modified_at': '2018-10-29T12:13:57-07:00',
 'name': 'Example User',
 'phone': '',
 'space_amount': 1000000000000000.0,
 'space_used': 14330011102,
 'status': 'active',
 'timezone': 'America/Los_Angeles',
 'type': 'user'}
>>>

To create a Client non-interactively with a developer token, construct an OAuth2 object with the access_token set to the developer token and construct the client with that.

from boxsdk import Client, OAuth2

auth = OAuth2(
    client_id='YOUR_CLIENT_ID',
    client_secret='YOUR_CLIENT_SECRET',
    access_token='DEVELOPER_TOKEN_GOES_HERE',
)
client = Client(auth)
me = client.user().get()
print(f'My user ID is {me.id}')

Server Auth with JWT

Authenticating with a JWT requires some extra dependencies. To get them, simply

pip install "boxsdk[jwt]"

Server auth allows your application to authenticate itself with the Box API for a given enterprise. By default, your application has a Service Account that represents it and can perform API calls. The Service Account is separate from the Box accounts of the application developer and the enterprise admin of any enterprise that has authorized the app — files stored in that account are not accessible in any other account by default, and vice versa.

If you generated your public and private keys automatically through the Box Developer Console, you can use the JSON file created there to configure your SDK instance and create a client to make calls as the Service Account by calling the appropriate static JWTAuth method:

from boxsdk import JWTAuth, Client

auth = JWTAuth.from_settings_file('/path/to/settings.json')
client = Client(auth)
service_account = client.user().get()
print(f'Service Account user ID is {service_account.id}')

Otherwise, you'll need to provide the necessary configuration fields directly to the JWTAuth constructor:

from boxsdk import JWTAuth, Client

service_account_auth = JWTAuth(
    client_id='YOUR_CLIENT_ID',
    client_secret='YOUR_CLIENT_SECRET',
    enterprise_id='YOUR_ENTERPRISE_ID',
    jwt_key_id='YOUR_JWT_KEY_ID',
    rsa_private_key_file_sys_path='CERT.PEM',
    rsa_private_key_passphrase='PASSPHRASE',
    store_tokens=your_store_tokens_callback_method,
)

access_token = auth.authenticate_instance()

service_account_client = Client(auth)

App auth applications also often have associated App Users, which are created and managed directly by the application — they do not have normal login credentials, and can only be accessed through the Box API by the application that created them. You may authenticate as the Service Account to provision and manage users, or as an individual app user to make calls as that user. See the API documentation for detailed instructions on how to use app auth.

Clients for making calls as an App User can be created with the same JWTAuth constructor as in the above examples, similarly to creating a Service Account client. Simply pass the User object for the app user instead of an enterprise_id when constructing the auth instance:

app_user = service_account_client.user(user_id='APP_USER_ID')

app_user_auth = JWTAuth(
    client_id='YOUR_CLIENT_ID',
    client_secret='YOUR_CLIENT_SECRET',
    user=app_user,
    jwt_key_id='YOUR_JWT_KEY_ID',
    rsa_private_key_file_sys_path='CERT.PEM',
    rsa_private_key_passphrase='PASSPHRASE',
    store_tokens=your_store_tokens_callback_method,
)
app_user_auth.authenticate_user()
app_user_client = Client(app_user_auth)

Client Credentials Grant

Allows you to obtain an access token by having client credentials and secret with enterprise or user ID, which allows you to work using a service or user account.

You can use CCGAuth to initialize a client object the same way as for other authentication types:

auth = CCGAuth(
  client_id="YOUR_CLIENT_ID",
  client_secret="YOUR_CLIENT_SECRET",
  user="YOUR_USER_ID"
)

client = Client(auth)
print(f'Id of the authenticated user is: {client.user().get().id}')

Obtained token is valid for specified amount of time, it will be refreshed automatically by default.

Obtaining Service Account token

The Service Account is separate from the Box accounts of the application developer and the enterprise admin of any enterprise that has authorized the app — files stored in that account are not accessible in any other account by default, and vice versa. To obtain service account you will have to provide enterprise ID with client id and secret:

auth = CCGAuth(
  client_id="YOUR_CLIENT_ID",
  client_secret="YOUR_CLIENT_SECRET",
  enterprise_id="YOUR_ENETRPRISE_ID"
)

Remember that you can still make calls on behalf of managed users, which are part of your enterprise, by using As-User bahaviour.

Obtaining User token

To obtain user account you will have to provide user ID with client id and secret

auth = CCGAuth(
  client_id="YOUR_CLIENT_ID",
  client_secret="YOUR_CLIENT_SECRET",
  user="YOUR_USER_ID"
)

In order to enable obtaining user token you have to go to your application configuration that can be found here. InConfiguration tab, in section Advanced Features select Generate user access tokens. Do not forget to re-authorize application if it was already authorized.

Traditional 3-Legged OAuth2

If your application needs to integrate with existing Box users who will provide their login credentials to grant your application access to their account, you will need to go through the standard OAuth2 login flow. A detailed guide for this process is available in the Authentication with OAuth API documentation.

Using an auth code is the most common way of authenticating with the Box API for existing Box users, to integrate with their accounts. Your application must provide a way for the user to login to Box (usually with a browser or web view) in order to obtain an auth code.

After a user logs in and grants your application access to their Box account, they will be redirected to your application's redirect_uri which will contain an auth code. This auth code can then be used along with your client ID and client secret to establish an API connection.

Redirect to Authorization URL

The first step in the process is to redirect the user to the Box Authorize URL, which you can generate (along with a CSRF token) by calling oauth.get_authorization_url(redirect_url) with your application's redirect URL.

from boxsdk import OAuth2

oauth = OAuth2(
    client_id='YOUR_CLIENT_ID',
    client_secret='YOUR_CLIENT_SECRET',
    store_tokens=your_store_tokens_callback_method,
)

auth_url, csrf_token = oauth.get_authorization_url('http://YOUR_REDIRECT_URL')

# Redirect user to auth_url, where they will enter their Box credentials

The SDK will keep the tokens in memory for the duration of the Python script run, so you don't always need to pass store_tokens.

Authenticate (Get Token Pair)

If you navigate the user to the auth_url, the user will be redirected to https://YOUR_REDIRECT_URL?code=YOUR_AUTH_CODE&state=CSRF_TOKEN after they log in to Box. After getting the auth code, you will be able to exchange it for an access token and refresh token.

The SDK handles all the work for you; all you need to do is call oauth.authenticate(auth_code) with the auth code pulled from the query parameters of the incoming URL:

from boxsdk import Client

# Make sure that the csrf token you get from the `state` parameter
# in the final redirect URI is the same token you get from the
# get_authorization_url method to protect against CSRF vulnerabilities.
assert 'THE_CSRF_TOKEN_YOU_GOT' == csrf_token
access_token, refresh_token = oauth.authenticate('YOUR_AUTH_CODE')
client = Client(oauth)

Initialize a Client Given Access and Refresh Token

You can also instantiate a client given the access and refresh token. You first need to construct an OAuth2 object with the access and refresh token passed in. Once you have created the oauth object you then pass it into your Client object to instantiate your client. Finally, you can begin making calls with your client.

from boxsdk import Client, OAuth2

oauth = OAuth2(
    client_id='YOUR_CLIENT_ID',
    client_secret='YOUR_CLIENT_SECRET',
    access_token='ACCESS_TOKEN',
    refresh_token='REFRESH_TOKEN',
)

client = Client(oauth)

user = client.user().get()
print(f'User ID is {user.id}')

Box View Authentication with App Tokens

Box View uses a long-lived access token that is generated from the Box Developer Console to make API calls. These access tokens cannot be automatically refreshed from the SDK, and must be manually changed in your application code.

To use the primary or secondary access token generated in the Developer Console, simply create a Client with that token:

from boxsdk import Client, OAuth2

auth = OAuth2(
  client_id='YOUR_CLIENT_ID', 
  client_secret='', 
  access_token='APP_ACCESS_TOKEN_GOES_HERE'
)
client = Client(auth)

As-User

The As-User header is used by enterprise admins to make API calls on behalf of their enterprise's users. This requires the API request to pass an As-User: USER-ID header. For more details see the documentation on As-User.

The following examples assume that the client has been instantiated with an access token belonging to an admin-level user or Service Account with appropriate privileges to make As-User calls.

Calling the client.as_user(user) method with the User creates a new client to impersonate the provided user. All calls made with the new client will be made in context of the impersonated user, leaving the original client unmodified.

user_to_impersonate = client.user(user_id='USER_ID_GOES_HERE')
user_client = client.as_user(user_to_impersonate)

Downscoping token

You can downscope a client's access token for one with a lower scope, in order to restrict the permissions for a child client or to pass to a less secure location (e.g. a browser-based app). This is useful if you want to use the Box UI Elements, since they generally do not need full read/write permissions to run.

To exchange the token held by a client for a new token with only item_preview scope, restricted to a single file, suitable for the Content Preview UI Element, call client.downscope_token(scopes, item=None, additional_data=None) with the scope(s) needed. This method returns a TokenResponse object with the downscoped token information.

target_file = client.file(file_id='FILE_ID_HERE')
token_info = client.downscope_token(['item_preview'], target_file)
downscoped_client = Client(
  OAuth2(
    client_id=None,
    client_secret=None,
    access_token=token_info.access_token
  )
)

But bear in mind that there is no way of refreshing this token, and you will need to add you own logic to do that.

Revoking Tokens

To revoke the tokens contained in an OAuth2 instance, removing the ability to call the Box API, call oauth.revoke().

oauth.revoke()