In the past, I’ve shown how to write RESTful API calls to VMware NSX and provided some sample code. However, after fielding some questions to folks, I’m taking this opportunity to dive a little deeper into how the basic authentication process works. It’s best to have a target platform to demonstrate against, so I’m using Rubrik’s r300 Hybrid Cloud Appliance and its RESTful API endpoint in this post.
Crafting a Basic Authentication Key-Value Pair
I’ve worked with quite a few different API endpoints supplied by infrastructure vendors, and most of them work in a manner that requires submitting credentials over and receiving back a token. The token is then used for subsequent requests in lieu of the original credentials. Rubrik is no exception to this trend.
When working with any system, however, it’s best to get their API documentation and see how they handle authentication. Basic authentication (“Basic Auth”) seems rather popular because it’s simple, whereas others may choose to use more exotic means (OAuth, HMAC, OAuth2, and so forth). Note that the use of SSL to encrypt the connection between the server and client is critical; I would advise never using Basic Auth over HTTP (plain text).
The idea behind Basic Auth is to send a header key-value pair that contains the credentials necessary to use a RESTful method. Here are the three steps:
- Take the string “username:password” and encode it using Base64. The colon between username and password is important, even if there is no password.
- Prefix this string with the word Basic, resulting in “Basic <Base64 value>”
- A header key of “Authorization” is created, with the above results stored in the value.
After this key-value pair is constructed, it will be placed into the header and look like this:
Authorization: Basic U3BvbmdlQm9iOlNxdWFyZVBhbnRz
But hey, where’s the token at?
Receiving a Token
While some API endpoints will let you stuff the Basic Auth details into the header of every API call (such as VMware NSX), others require that you submit the login credentials to a specific method to receive a token. In Rubrik’s case, we first require that you log in by using a POST to the /login resource with a parameter containing the username and password in the body. Here’s the details from Swagger-UI.
The response class shows that a properly formatted call should result in a 200 status (OK) and you’ll get back a status, description, userId and token key-value pair.
Easy enough! Here’s the code I’ve written for the Connect-Rubrik cmdlet found in the Community PowerShell Module for Rubrik. Its purpose in life is to gather credentials and acquire a token that will be used in subsequent cmdlets. While I don’t profess to be any sort of expert in this arena, I did want to share what was created in hopes of sparking a fire in others and learning how to better write this sort of code.
Note: the /login resource does not require Basic Auth because that wouldn’t be possible – you have to first authenticate before you can start using the resulting token. 🙂
Breaking Down the Code
The real action starts with line 54. This is where the Uniform Resource Identifier (URI) is constructed to talk to the appropriate resource, which is /login for this example. I’m using variables gathered earlier in the script that are defined in the Param section (server, username, and password). Note that password is a SecureString variable to protect the contents.
Next, the credentials are constructed on lines 57-61. The SecureString variable is a bit tricky to work with, so I first create a PSCredential variable to gather up the username and password, and then break it back down into the key-value pairs required by the /login resource.
Lines 64-74 are where the API call occur using Invoke-WebRequest. As I’ve mentioned in earlier posts, I prefer this cmdlet over Invoke-RestMethod because it returns the entire response, not just the content portion. I’m also using an on-the-fly conversion of the $body hashtable (key-value pairs) into JSON with the super handy ConvertTo-Json cmdlet. Finally, I retrieve the resulting token value from the content of the response.
The final portion involves lines 78-82, which constructs a global variable for future Basic Auth requests. This avoids needing to construct the variable for future calls used by other cmdlets. I had to leverage a bit of native .NET code with [System.Convert]::ToBase64String to encode the string for Basic Auth. In our case, the token becomes the username and there is no password anymore. The results are stored into the key named Authorization as per Basic Auth requirements.
Using Basic Auth in Subsequent Calls
Let’s see how the global variable that contains the Basic Auth value is used for other cmdlets. Using the New-RubrikMount cmdlet as an example, which creates a zero-space clone based on a backup point, we can see the code in action.
Lines 33-38 are validating that the global token variable exists to make sure that you’ve used Connect-Rubrik in the past. A simple true/false test is all it takes.
The other sections (line 44, 64, and 99) are all using Invoke-WebRequest to the Rubrik API and leverage the $global:RubrikHead variable, which contains the Basic Auth key-value pair required for authentication. Notice that within PowerShell, this is as simple as using -Headers $global:RubrikHead. The header could contain more keys than Authentication, but for my purposes that’s the only key required. The global variable can be re-used across all of the Rubrik cmdlets, although I’m sure there are some better ways to securely store the token, despite the fact that it expires after a short while.
So, there you have it. It’s been fun to learn how to make all of these pieces work via PowerShell, and it’s really exercised my noodle a fair bit. If you have suggestions for improvement, please send me a pull request (PR) or file an issue. 🙂