One of the many exciting features of the Madrid release is that inclusion of JWT (JSON Web Tokens) as a supported authentication type. Before this feature, I had been working with very limited success to help a Box user integrate with ServiceNow via JWT. JWT are non-trivial to construct and require access to cryptographic tools, so having them in the platform is a big step up.
I’m going to walk through the steps I took to get an integration working with Box. As a warning, this is quite fiddly and on both ends of the transaction. I’ll be doing everything from the Mac perspective and it does require some work at the command line. If some kind reader wants to send me the Windows equivalent commands to email@example.com or leave in comments below, I would happily edit those in. With any luck, this example will help get stuck developers over the trouble spots.
As I walk through the steps I took, I’ll basically be collating the official documents explaining the integration from both the ServiceNow side and the Box side. Integrating to other systems via JWT will certainly have their idiosyncracies but in this one we’ll be focusing solely on Box.
Step 1 - Enable Plugin
In order to have JWT available as an authentication type, you must first enable the plugin. That plugin is “Integration - Multiple Provider Single Sign-On Installer” with id com.snc.integration.sso.multi.ui . After that is activated, JWT will be an option for authentication and inside the X509 Certificates.
Step 2 - Create a Box Application
Although all ServiceNow employees have Enterprise accounts with Box, I created a personal account so I could create an application without the intervention of our corporate Box Enterprise administrators. If you are doing this within your Enterprise account, this may and probably will require some admin attention.
First open the Box developer console and click the “Create New App” button. For this example I created a “Custom App” and then chose “OAuth 2.0 with JWT” as the authentication type. The Box documentation suggests that you use their functionality to automatically generate a public/private key pair but I was unable to make those generate keys work with the ServiceNow keystore so I suggest you skip that.
Step 3 - Create a Java Keystore and Public Key
In order to generate the JWT from the ServiceNow side, ultimately there will need to be a Java keystore that matches the key for the Box app. After much fiddling and googling about importing and exporting RSA keys, I was never able to get the Box keys into a Java keystore. I ended up going the other direction, creating a new keystore and exporting a public key from that, which I then uploaded to Box. However even that wasn’t a straightforward process. If you know of better ways, again, leave a comment below.
First, I created a keystore using keytool.
keytool -genkeypair -keyalg rsa -keysize 2048 -alias box -keystore box.jks -dname "CN=Dave Slusher"
You will be prompted for a password for the keystore. Keep up with this, you’ll need it several times including the very next step.
Next, I exported a certificate in PEM format from the keystore
keytool -exportcert -rfc -alias box -keystore box.jks > box.cer
Now, given this certificate I used openssl to convert it to an RSA public key
openssl x509 -inform pem -in box.cer -pubkey -noout > box.pub
The final output of this step generates the final usable public key. This is what is uploaded to Box as the public key for use in signed requests.
Step 4 - Create JWT Records in the ServiceNow Instance
All of that was prelude to actually beginning the ServiceNow portion of the work. Now it is time to create the JWT related records in the instance. There are three records to create.
First is the X509 certificate. Navigate to Multi-Provider SSO > x509 Certificate and create a new record. The key values here are the type which will be Java Keystore and the key store password which is the same one you used when creating the keystore at the command line. After submitting or saving the record, you must also add the .jks file to this record as an attachment or it won’t work. This is completely not obvious but is crucial to making this work.
After creating this record and attaching the JKS file, click the Validate Stores/Certificates related link. This will tell you immediately if this is configured correctly.
Next up is the JWT signing key. Navigate to System OAuth > JWT Keys and create a new record. The Signing Keystore will be the one you just created, the Key Id is the alias you used when creating the keystore (“box” in my case) and the Signing Key Password is also the password for the keystore. Yes, you have to enter it again here and no, I don’t know why.
Now create a JWT provider. Navigate to System OAuth > JWT Provider and create a new record. Expiry Interval will be the lifetime in seconds of the JWT created by this provided and Signing Configuration is the JWT Key from the previous step.
There will be some default entries created in the Standard Claims related list. “aud”, “sub” and “iss” will be created with type string, but with empty values. In addition, you will need to add one not auto-generated called “box_sub_type”. The values will be:
Claim Name Claim Value aud https://api.box.com/oauth2/token iss < Client ID from the Box app > sub < Enterprise ID or User ID from the Box app > box_sub_type enterprise or user
If you are in fact using the enterprise rather than the user as the basis of the login, then you would alter the values above to be “enterprise” for box_sub_type and then use the Enterprise ID from Box.
With all this, the JWT portion is complete but we are not done by a long shot.
Step 5 - Create the OAuth Configuration
All that was fun stuff, but now we have to create the OAuth pieces to actually use the JWT. I’ve found OAuth challenging in the past, which is why I left myself (and you too) this nice resource explaining it .
First, navigate to System OAuth > Application Registry and then click New. On the interceptor page, click Connect to a third-party OAuth provider and then fill in the form.
Important values you will need for this record are the Client ID and Client Secret from your app on Box; Default Grant type is JWT Bearer; Token URL which for Box is https://api.box.com/oauth2/token . The Redirect URL needs to exist, but leave it blank and the correct value will be filled in automatically.
An OAuth Entity Profile will be created automatically. An You will need to open this record and add the JWT Provider created above. This will be impossible to miss because an error message to that effect will be presented on creation of this record.
In the OAuth Entity Scopes related list (of the Application Registry, not the Profile from immediately above), you will need to specify every scope that you are requesting via this integration. In my case, out of convenience and laziness I chose “root_readwrite” but you might want to be more granular than that based on the needs of your integration and the security requirements of your organization. The scopes Box provides are listed here. For any that you wish to add, you give it a name and then the value from Box. I never see much reason to have them differ so I use the same thing for both.
Step 6 - Configure the Box App
At this point the ServiceNow end is configured and ready to go. A few final bits of configuration have to be aligned in order to make the integration function properly. Some of these bits were extremely non-obvious to me so do save yourself some frustration and examine your app closely.
Although we created the public key above, we never have yet put it in the app. From the configuration page of your Box app, scroll down to the Add and Manage Public Keys section and click Add a Public Key. You’ll paste in the text of the key you created earlier.
Even though this app was created in my personal account, it still needs to be enabled by the “Enterprise.” This part confused me and blocked me for a while. If doing this as a corporate-wide integration this would involve IT and the administrators of the account. In my case, I still had to go to the Admin Console. click Enterprise Settings in the left navigation, then Apps in the top nav and scroll down to Custom Apps. From there, you click Authorize New App. It will ask for the “API key” for your app which is really the Client ID from the Box app.
Step 7 - Take it for a Spin
After all this set up, you should now have a Box application and a matched set of OAuth configurations that can access it. Now it is time to do the real work: hit the API!
In Servicenow, create a new REST Message. Set the authentication type as “OAuth 2.0”, the OAuth profile as the one you set up above, and the endpoint as anything from the Box API. A good default one is https://api.box.com/2.0/folders/0 which gets the information about the folder with ID 0, aka your default folder. After saving or submitting, you’ll see “Default GET” in the HTTP Methods related list. After the page refreshes you’ll get a message saying that OAuth is configured but there is no token. Under Related Links will be Get OAuth Token. Click that link and it will initialize the JWT request. This is the one and only time you will need to click that link. After this, the token will auto-refresh up to the time you specified in the Application Registry entry’s Refresh Token Lifespan field.
With that, you are integrated to Box! From that REST Message you can navigate to the HTTP Method entry and test the API call. If you received errors either on generating the OAuth token or accessing the API, you may have to do some troubleshooting. You may need to verify that the Box application is authorized, that the scopes match, that the Client IDs and Secrets configured on the ServiceNow side match the Box app side, etc etc.
I am very interested in the reception to this post. As you can see from the length and details of this post, it isn’t a casual process to create this integration. If you have problems, tricks or tips from your experience, please leave them in the comments below.
Thanks for your time and happy integrating!