Monday, June 30, 2014

Using PowerShell to Manage Box.com - Part 2: Using PowerShell to register your Box app on your workstation

If you've gotten here before reading part 1 of this series you want to read that first.  I has some important information that will help make sense of what this post is about.

Now that we've registered our application with developers.box.com, we need to grant our Box account access to use it.  I created a function in PowerShell that will bring you to the Box app site (which allows you to grant permission) and then grabs the information returned by Box and write it to your workstation's registry.

Just a little back ground (for a complete understanding read Box's official OAuth 2.0 document).

Basic layman's terms
In order to use the app you registered with Box, Box's OAuth2 implementation requires that you grant your Box account access to the application.  The granting process is an interactive process within your browser.  So you can't just write a script to carry out the granting process.  Once you've granted permission to the app, Box will redirect your browser (remember the redirect_uri) to a site you configured in the app.  The address bar contains the URI specified by the redirect_uri and appends a security token (which will be arbitrarily set during the registration process) and the initial authorization code.

The initial authorization code has a very short life.  It will expire within 30 seconds.  So if you don't use it to to retrieve your access token in time, you will have to go through the granting process again.
NOTE:  You can go through the granting process as many times as you like.  My PowerShell function actually makes it a rather painless process.

Once you get your authorization code you will need to leverage Box's RESTful API (within 30 seconds) to obtain an access token.  The API returns 5 attributes that my PowerShell function writes to your workstation's registry.

  • access_token #This is the actual token needed to issue commands against Box's APIs
  • expires_in #This is the life of the token (always roughly 1 hour give or take a few minutes)
  • restricted_to #This always comes back blank for me and I haven't had a need for this attribute
  • refresh_token #After the one hour expiration of your access token you will need to use this token to get a new access token.  All of my functions first check to see if the current access token is expired, if so it will refresh automatically.
  • token_type #I'm not sure of all the types, but we will be dealing with the 'bearer' type.
So let's take a look at the actual PowerShell function that does all of that:

[edit]
NOTE:  I make calls to Test-RegKey, Set-RegKey, Set-RegValue.  These are not cmdlets that are built into PowerShell.  Instead, they are part of a suite of registry function that I created during one of the Scripting Games I participated in a few years ago.  I keep them in a separate module which you can download here.

I re-wrote the function to use PowerShell's native ability to access the registry (new-item, set-itemproperty, get-itemproperty, test-path).  You no longer need to import the RegEditSuit.psm1 module.

Here is the function:


Let's break the function down:
First the parameters:

  • $AppName 
    • This is actually an arbitrary name you give for registration purposes.  I used the same name I provided when I registered my application on Box.com.  While it arbitrary, remember that a registry key will be created for this app and that the Box function I create reference the registry key that gets created.  So you will want to remember the name you give it.
  • $ClientID
    • You recorded this string when you registered the application on Box.com.  You will need to provide that string.
  • $ClientSecret
    • You recorded this string when you registered the application on Box.com.  You will need to provide that string.
  • $APIKey
    • This is actually the $ClientID.  I personally like to record it into my workstation registry as APIKey, but it is not required to use any of the Box functions I created.
  • $SecurityKey
    • This is an arbitrary string.  The function has a default one.  The official Box documentation recommends that you use an anti-forgery state token to prevent CSRF attacks to your users.  But I believe that is for mobile apps you will publishing to their app store.  I don't think that forgery is an issues for colleagues that may be using your PowerShell scripts (imo).
So the first thing the script does it to make sure that a registry key exists under HKLM\software\box.com\.  If it doesn't exist then it creates it.

You can register multiple apps.



It then records the Client_ID, Client_Secret, and the APIKey at the root of that registry key.
It next runs through the interactive granting authorization process to retrieve the authentication code.  It starts by opening IE and navigating to a URI that includes the Client_ID and the arbitrary security key.  Then pops up a msgbox with instructions to finish the interactive authorization in IE before clicking OK. 

Let's take a look at what that process like in IE.
IE Opens to an Authentication Page
Once Authorized Grant or Deny Access
The site I land on I created additional instructions.  The green box shows the arbitrary security key for validation and the red box shows the authorization code.
Back in PowerShell click the OK button and PowerShell will grab the authorization code out of the LocationURL value.



Back to 'Register-BoxApp' function:
Once you click OK the function next loads up a hashtable with the AuthCode, clientID, clientSecret, it sets the RESTful URI and then invokes the RestMethod.

Here is the outcome in PowerShell of waiting too long (more that 30 seconds) to click the OK button.
Here is the outcome in PowerShell if you successfully click the OK button with 30 seconds.
If you wait too long to click OK this is the error you get.  Code is good for 30 seconds.
Results for successfully clicking OK within 30 seconds.

You may notice that after the Invoke-RestMethod line in the Register-BoxApp function, if there is a Access Token, the script will run the 'Register-BoxAccessToken'.  Here is what that function looks like:
[Edit]
Note:  I re-wrote the function to use PowerShell's native ability to access the registry (new-item, set-itemproperty, get-itemproperty, test-path).



Because the return data type of Invoke-RestMethod to Box is JSON, Invoke-RestMethod returns a PSCustomObject.  That means I have to provide the property names of the object ($RegValueNames) - unlike a hashtable where I could request the keys and interate through the key names to accomplish the same thing the function does with the PSCustomObject.

You will notice in the 'Register-BoxAccessToken' function as I'm iterating through the valuenames I check to see if the value name equals 'expires_in'.  That is because the data returned from Box is the number of seconds the access code is good before it expires.  So I create a datetime object and add the seconds to it and convert it to a string to store in the registry.  In a later post you will see how a function called 'Get-BoxAccessToken' exploits that datetime object in order to determine if the token needs to be refreshed.

If all goes well then AccessTokenInfo is written to your workstation's registry.
BoxAccessToken is a sub key and the access token, expires_in, and refresh token are registered here.

In the next post, I will discuss the functions 'Get-BoxAccessToken' and 'Refresh-BoxAccessToken, which are incorporated in all the work functions you will create in the future.

I've uploaded the entire OAuth2 PowerShell module for you to grab here.

2 comments:

  1. Cameron, this is fantastic! I need to use PowerShell to automate tasks on Box. When will you publish part 3 and will it include samples of your provisioning code?

    ReplyDelete
  2. Great work! One small change needed in line 28; the URL needs to be

    https://api.box.com/oauth2/authorize?....

    Also, I'm dying for part 3!

    ReplyDelete