Accessing Box’s API via OAuth2 & Python’s Requests Module

Standard

box-company-logo

As mentioned before, when using Box with ADFS for SSO there are more than a few limitations.

In an attempt to overcome them, I took on Box’s API. The first hurdle was trying to connect to it as Box uses OAuth2 which massively differs from other API authentication for other API’s I’ve access such as Airwatch.

However, I’ve a method & in I’ve detailed it below. This method is used throughout all my Box API scripts.

Box Python SDK

Box do have a Python SDK, but as I’m working across multiple API’s which do not have modules for them, I wished to have a more standardised approach.

The Python SDK may certainly be a better approach for many.

OAuth2

OAuth2 massively differs when it comes to authentication from API’s such as those used by Airwatch or JAMF which just require a username or password to be passed.

There are few steps to follow to create an account with Box first, then a handful of tokens to juggle.

Codes & Tokens

The main juggling act comes from the codes & tokens used to complete the OAuth2 process & their life.

Authorization Code

Once you’ve gone through the below, you’ll have generated an Authorization Code.

This code lasts for 60 seconds & is used in the initial request to generate the Access & Refresh Tokens.

Access Token

The Access Token is the token you’ll need to use to make API calls. This token is only valid for 60 minutes, but can be used multiple times within the 60 minutes.

Refresh Token

The Refresh Token is used to generate new Access & Refresh Tokens.

This has a 60 day validity period & can only be used once.

So, the method employed by the script is to generate a new Refresh Token with every run & write this to a plist so that subsequent runs will use the last generated Refresh Token to generate the Access & Refresh Tokens.

Requirements

The following are a list of things needed before we get started.

Requests Module

Currently I have 3 systems with REST API’s that I wish to script, AirWatch, Box & JSS, as such I wanted to try & standardise my approach across all 3 as much as possible & not use any bespoke libraries.

Whilst Python has many modules built in that greatly assisted me, when it came to REST API scripting the external library “Requests” was recommended & it’s awesome.

As this is an external module, (at least on OS X which is the OS I’m running my API scripts on), we need to run a couple of commands to install the Requests Library on OS X.

These are show below:

sudo easy_install pip

sudo pip install requests

With the Requests module installed, we can then import it within scripts or the Python interpreter using the “import” command.

The below are quotes taken from the “Requests” site that give a short insight into the library:

Requests is an Apache2 Licensed HTTP library, written in Python, for human beings.

Requests takes all of the work out of Python HTTP/1.1 — making your integration with web services seamless. There’s no need to manually add query strings to your URLs, or to form-encode your POST data. Keep-alive and HTTP connection pooling are 100% automatic, powered by urllib3, which is embedded within Requests.

A Folder

One last thing we need is a folder to write logs to &, if wanted, to hold the script.

The account running the script needs to have RW access to the folder.

This is a simple thing, but mentioned to avoid any tripping up.

As mentioned, I’m running these scripts on OS X & have multiple running. So I like one folder per REST API I’m scripting against.

Box Account

All my API scripts for Box are to be used to administer an enterprise instance, therefore an Enterprise Admin account is needed.

This script itself does not need an account of that level. But if administering an enterprise instance is something you’re looking at, then I advise you start with an account of that level as it’s easier.

A Copy Of The Script

I’d advise you make a copy of the script at the end of this post & populate the variables as you go, there are a few & the last one you have 60 seconds in which to use it!

Preliminary Steps

Taken & amended from: https://box-content.readme.io/docs/oauth-20

  1. Register your application here.
  2. Set your redirect url (set this to http://127.0.0.1 for this script)
  3. Select your scope
  4. Make a note of both your client_id and client_secret.

With the above, I’d advise you start populating the scripts variables & then proceed with the next section.

Secondary Steps

With the scripts variables set, we can now proceed.

Append the client_id to the following URL, then copy & paste into a browser:

https://app.box.com/api/oauth2/authorize?response_type=code&client_id=

You should then be redirected to Box, & if not currently logged in see something like the below:

Once authenticated, you’ll need to the grant “application” access to Box:

Next, you’ll be redirected to the redirect url, (which should be http://127.0.0.1). This will redirect you to a page like the below, but it’s not in error.

Screenshot 2016-01-20 22.34.27
Grab the text after ‘code=’ within the URL & set the scripts authorizationCode variable to this value.

Next, run the script. But keep the above window open for now, if we run into any token generation issues you can press the browsers back button, grant access again & generate a new authorization code.

All being setup correctly the script should use the authorizationCode to generate both an Access & a Refresh Token, with the refresh token being written to the plist (a long with time generated).
Screenshot 2016-01-20 22.54.19
Refresh Token key from the plist, then make an API call to generate new access & refresh tokens. Again the script writes the newly generate Refresh Token to the plist for the next run or API call.

Email & Log

The script logs all actions to a log, which it overwrites with every run.

The contents of which are then emailed to the address specified, including if the script encounters any errors with the subject advising what’s happened.

ScopeScreenshot 2016-01-20 22.08.37

It’s worth noting that when changing an accounts scope, you’ll need to follow the below to generate new tokens for the accounts scope to be updated.

Variables

The script declares several variables within it some are generated within the script & others are for you to supply, the below is some detail as to what they do.

For each variable that needs supplying, please enter the relevant values in the ‘ ‘ of the variable.

oauth2URL

SET: This URL is the URL used to obtain the OAuth tokens & is set to https://app.box.com/api/oauth2/token.

apiURL

SET: This URL differs from the above & is used for all API requests.

authorizationCode

SUPPLY: Leave this blank for now, we’ll generate this in a few & once you do you’ll have 60 seconds to run the script.

clientId

SUPPLY: Set this variable to the client_id created in ‘Initial Steps’

clientSecret

SUPPLY: As per the client_id, this is the client_secret created in ‘Initial Steps’

apiFolder

SUPPLY: The folder to write the log to.

logFileFullPath

GENERATED: This take the variable apiFolder & scriptName & generates a path to create a log. For example: /my/folder/my-script.py.log

plistFileFullPath

SET: The script writes the generated refresh token to a plist within the apiFolder. This token will then be used whenever the script is run or when other Box API scripts are run (as long as using this script as a template).

mailServer

SUPPLY: Used by then sendEmail function (more on this below) to send an email with the contents of the log file

mailFrom

SUPPLY: The email address for the email to be sent from.

mailTo

SUPPLY: Email address to sent the email too.

scriptName

GENERATED: This variable gets the name of the script, as I’m running multiple scripts against the REST API it’s handy to have the logs & notifications for them to be separate & noted as to where they come from.

logging.basicConfig

GENERATED: This configures the logging for the script, for now leave it as is. This will generate a log in /my/folder/my-script.py.log like the below:

2016-01-20 20:58:10,454 INFO Using Refresh Token: R75MmVYSPdj68ZTTt1RWEkIU7mxsGT2wl6hEGRDQDzH7plSQ2lUHZmg5UlLv30N6
2016-01-20 20:58:10,463 INFO Starting new HTTPS connection (1): app.box.com
2016-01-20 20:58:11,523 DEBUG "POST /api/oauth2/token HTTP/1.1" 200 None
2016-01-20 20:58:11,529 INFO Generated Access Token: BxkoX8FIU3T9f0mIgxzWMTRUQKCoYMxL
2016-01-20 20:58:11,529 INFO Generated Refresh Token: gbLAw3T1duTPdVPkMiARE4CJ896De6RFkrWgybfnh6eAKq5lBdO8F8TzzIV2iBD7

The Script

Below is the script itself & it can be found here.

As mentioned this script is merely getting generating & refreshing tokens, & (with the usual caveats) is safe to run against your Box instance.

8 thoughts on “Accessing Box’s API via OAuth2 & Python’s Requests Module

  1. Alan

    Excellent article that has helped me to progress a great deal – some pics are missing however. I have a few problems getting the token to generate though and am getting errors on two lines:

    logging.info(‘Using Refresh Token: %s’ % refreshToken)

    and the last all important line:

    generateTokens()

  2. Alan

    I changed a bunch of the email notification code you have inserted to provide print feedback rather than email because it added complexity and delay due to routing through email servers.

  3. Sumit

    Thanks a lot the script. It is working as expected. I want to write a script to upload files from local to box.
    The script that you have provided is working and it is generating access and refresh tokens, but how do I use it in the script? another question is, how do I use refresh token? Please help me achieve this.

  4. Farrakh

    How will user submit username and password here?

    I am expecting a dialog box appears for that but i don’t get it?

    Is it what should be expected when running post for creating “authorization_code”?

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.