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.
Contents
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
- 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.
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 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.
Scope
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.
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 & as mentioned this script is merely getting generating & refreshing tokens, & (with the usual caveats) is safe to run against your Box instance.
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()
Alan, how did you solve the problem with the token refresh?
old old post.. but updated due to https://macmule.com/2021/11/17/where-did-the-code-examples-go-well/.. still can’t find the images so amended.
I have it working. Can’t thank you enough
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.
Cool!
I do have another version to post that has been pylinted.. just time 🙁
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.
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”?
this should be detailed in the post