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 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.
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.
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.
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.
The following are a list of things needed before we get started.
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.
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.
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!
Taken & amended from: https://box-content.readme.io/docs/oauth-20
- Register your application here.
- Set your redirect url (set this to http://127.0.0.1 for this script)
- Select your scope
- 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.
With the scripts variables set, we can now proceed.
Append the client_id to the following URL, then copy & paste into a browser:
You should then be redirected to Box, & if not currently logged in you’ll be prompted to login.
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.
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).
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.
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.
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.
SET: This URL differs from the above & is used for all API requests.
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.
SUPPLY: Set this variable to the client_id created in ‘Initial Steps’
SUPPLY: As per the client_id, this is the client_secret created in ‘Initial Steps’
SUPPLY: The folder to write the log to.
GENERATED: This take the variable apiFolder & scriptName & generates a path to create a log. For example: /my/folder/my-script.py.log
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).
SUPPLY: Used by then sendEmail function (more on this below) to send an email with the contents of the log file
SUPPLY: The email address for the email to be sent from.
SUPPLY: Email address to sent the email too.
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.
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
Below is the script itself & as mentioned this script is merely getting generating & refreshing tokens, & (with the usual caveats) is safe to run against your Box instance.