Start a new topic

Working with JSON Web Tokens (JWT)

One of the authentication methods available for the Commander API is a standard called "JSON Web Tokens" or JWT.
Using JWT can be a bit more involved than basic auth but it offers stronger security and is required to use the Multi Tenant API.

In this post I will show you some tricks for using JWT in Python and PowerShell.

Typically when making a request from PowerShell you would do something like the following

$user = "admin"
$password = "12345"
$creds = New-Object System.Management.Automation.PSCredential ($user, $password)
$uri = "https://my.commander.local/rest/v3"

$response = Invoke-RestMethod -Uri "$uri/organizations" -Method GET -Authentication Basic -Credential $creds


Or in Python (with the "requests" module)

import requests
user = "admin"
password = "12345"
uri = "https://my.commander.local/rest/v3"

response = requests.get(uri + "/organizations", auth=(user, password))



As you can see, basic authentication is trivial and requires no set up.

JWT requires the extra step of requesting a signed token. This is usually done by posting to an endpoint with
valid username and password. In Commander's case that is the '/tokens' endpoint.

Here's an example:

$payload = @{
    username = $user;
    password = $password | ConvertFrom-SecureString -AsPlainText
} | ConvertTo-Json

$response = Invoke-RestMethod -Uri "$uri/tokens" -Method POST -Body $payload -ContentType "application/json"
$token = $response.token | ConvertTo-SecureString -AsPlainText # Invoke-RestMethod expects secure string


And in Python:

payload = {
"username": user,
"password": password,
"organization": "org"
}

response = requests.post(uri + "/tokens", json=payload)
token = response.json()['token']


A JWT token contains signed data that the server can use to validate the users session. This means that once you
have a token, you don't need to send your password again, you just need to send the token.
The token string is sent along in the "Authorization" header as a "bearer token".

(For more information about how JWT works, see https://jwt.io/)

To make an API request using our token, we would do something like this:

$response = Invoke-RestMethod -Uri "$uri/organizations" -Method GET -Authentication Bearer -Token $token


Very simple!
And in Python:

response = requests.get(uri + "/organizations", headers={"Authorization": "Bearer " + token})


(Side note, in both PowerShell and Python there are modules that can help with REST API's and JWT, but it is helpful to understand how it works!)

Because of the enhanced security model of JWT, tokens typically are set to "expire" after a number of minutes (configured by the particular application server)
This means that for long running scripts you may have to refresh your token before sending another request.

If you "decode" a JWT token you can see the expiry date in one of the payload keys:

import base64
from datetime import datetime
decoded_payload = base64.b64decode(token.split('.')[1])
expiry = datetime.fromtimestamp(decoded_payload['exp'])


Alternatively you can just check when you have an expired token by catching unauthenticated exceptions.
In Commander, tokens must be refreshed within 60s and expire after 15 minutes.

You can refresh a token by posting it back to the /tokens/refresh endpoint

$payload = @{token = $token | ConvertFrom-SecureString -AsPlainText}
$response = Invoke-RestMethod -Uri "$uri/tokens/refresh" -Method POST -Body $payload -ContentType "application/json"
$token = $response.token | ConvertTo-SecureString -AsPlainText


Python:

response = requests.post(uri + "/tokens/refresh", json={'token': token})
token = response.json()['token']


This returns a new token with an updated "access expiry". This new token is valid for another 60s without having to re-auth.
After 15minutes from the first token, the token cannot be simply refreshed and you must re-authenticate to get a new token.

For longer and more complex scripting tasks, I would recommend writing some routine to check the token before every request.
As an example, in Python you might have a Auth class for using with requests. In PowerShell you might wrap your Invoke-RestMethod
in another function which checks the token before making the request.

I hope this gives you a good starting point for working with JWT in your integrations both with Commander and other OAUTH/JWT applications.
Please feel free to leave any questions or comments!

Login or Signup to post a comment