API examples in cURL

Introduction

The OneLogin documentation at https://developers.onelogin.com/api-docs/1/getting-started/dev-overview describes the RESTful interface for accessing API calls to query and update a OneLogin subdomain with JSON formatted data. Where experienced programmers may already understand use of a RESTful API the reference material stands on its own but administrators with no specific programming experience can also use the API in simple scripts. This document assumes some familiarity with shell scripting and aims to demonstrate how the API can be leveraged using the ‘curl’ command to do most of the work (see https://curl.haxx.se for details on curl). It is also possible to do the same work with the PowerShell InvokeRestMethod command in Windows, but this is out of scope for this document. As a basic assumption, it is assumed that the curl command is present on your system (as is true for an Apple Mac and many flavours of Linux and UNIX).

Access token

Most access to the API is governed by the creation of an Oauth 2.0 access token which is then used to authorize any of the subsequent commands.

Example

The curl command can be used at a UNIX/Linux/Mac command line to make a call to the OneLogin API and get a result, for example: -

$ curl -H 'Authorization: client_id: f41e276e878f1960e775527beaaa64decfb0eb86207a3e08832a8f66874aa2c9, client_secret: f58ef564938e5fb976f31b6be8ed660cbee0f376faae66e8406c959aba0d5b8d -H 'Content-Type: application/json' -d '{"grant_type":"client_credentials"}' https://api.us.onelogin.com/auth/oauth2/v2/token

{"access_token":"85dcd87b8fe7d4704ef27359a05d18271053dbd33ccfacdca29a5cb18bc72190","created_at":"2018-08-24T22:16:49.617Z","expires_in":36000,"refresh_token":"738e673cb12792bdd5a47204096232ca3328311876354c9a5be21be2c4f6e5d1","token_type":"bearer","account_id":1060299}

$

Command breakdown

The previous example shows the curl command run with a series of parameters and the result back as a JSON string. We can break down both input and output with some carriage returns to make it more readable:

Basic Curl Example


curl 
-H 'Authorization: 
    client_id:
      f41e276e878f1960e775527beaaa64decfb0eb86207a3e08832a8f66874aa2c9,
    client_secret:
    f58ef564938e5fb976f31b6be8ed660cbee0f376faae66e8406c959aba0d5b8d' 
  -H 'Content-Type: application/json' 
  -d '{"grant_type":"client_credentials"}'
  https://api.us.onelogin.com/auth/oauth2/v2/token
   
{
  "access_token": 
  "58dcd87b8fe7d4704ef27359a05d18271053dbd33ccfacdca29a5cb18bc72190",
  "account_id": 10602999,
  "created_at": "2018-08-24T22:16:49.617Z",
  "expires_in": 36000,
  "refresh_token": 
  "738e673cb12792bdd5a47204096232ca3328311876354c9a5be21be2c4f6e5d1",
  "token_type": "bearer"
}

This is using the curl command with minimal parameters showing the least work to get a result and you leave the internals of the command to make assumptions as to how best to work. Subsequent examples will have extra parameters to enforce specific functionality and avoid default behaviour which might change between platforms, for example: -

Curl Example with Indents

curl 
     -s 
     -X POST 
     -H 'Authorization:
      client_id:
        f41e276e878f1960e775527beaaa64decfb0eb86207a3e08832a8f66874aa2c9,
      client_secret:
        f58ef564938e5fb976f31b6be8ed660cbee0f376faae66e8406c959aba0d5b8d' 
     -H 'Content-Type: application/json' 
     -d '{"grant_type":"client_credentials"}' 
     https://api.us.onelogin.com/auth/oauth2/v2/token

In this example there are three variables which will differ for customers

  1. The client_id value (f41e276e878f1960e775527beaaa64decfb0eb86207a3e08832a8f66874aa2c9)
  2. The client_secret value (f58ef564938e5fb976f31b6be8ed660cbee0f376faae66e8406c959aba0d5b8d)
  3. The shard where the customer system resides (us)
If we put this into a shell script for repeated use we can set up a series of parameters to cope with different options (here we will still hard-code the variables into the script for the demonstration)

Example: demo1.sh

#!/bin/sh
#
# demonstration script 1 (not supported)
#
# Using the curl command to generate an access token
# setting some shell variables to pass into the command
# using a line break option and spacing to avoid screen wrapping and aid readability.
# This example uses single quotes
#
#  Set the shell variables
#
CLIENT_ID=f41e276e878f1960e775527beaaa64decfb0eb86207a3e08832a8f66874aa2c9
CLIENT_SECRET=f58ef564938e5fb976f31b6be8ed660cbee0f376faae66e8406c959aba0d5b8d
SHARD=us

curl \
        -s \
        -X POST \
        -H 'Authorization: client_id:'${CLIENT_ID}', client_secret:'${CLIENT_SECRET}'' \
        -H 'Content-Type: application/json' \
        -d '{"grant_type":"client_credentials"}' \
        https://api.${SHARD}.onelogin.com/auth/oauth2/v2/token

#
# For security, in case this script is run using the . command, unset the variables we used
#

CLIENT_ID=
CLIENT_SECRET=
SHARD=

Notice the multiple uses of the singe-quote. This is standard within shell scripting to allow variables to be inserted into command where quote mares are already being used. This works but is hard to maintain so we will now make use of some temporary script variables to cope with this.

The same result can be obtained using double-quotes, except here we must cope with the need to send double-quote characters as part of our input as well

Example: demo2.sh


#!/bin/sh
#
# demonstration script 2 (not supported)
# 
# Using the curl command to generate an access token
# setting some shell variables to pass into the command
# using a line break option and spacing to avoid screen wrapping and aid readability.
# This example uses double quotes
#
#  Set the shell variables
#
CLIENT_ID=f41e276e878f1960e775527beaaa64decfb0eb86207a3e08832a8f66874aa2c9
CLIENT_SECRET=f58ef564938e5fb976f31b6be8ed660cbee0f376faae66e8406c959aba0d5b8d
SHARD=us

curl \
	-s \
	-X POST \
	-H "Authorization: client_id:${CLIENT_ID}, client_secret:${CLIENT_SECRET}" \
	-H "Content-Type: application/json" \
	-d "{\"grant_type\":\"client_credentials\"}" \
	https://api.${SHARD}.onelogin.com/auth/oauth2/v2/token

#
# For security, in case this script is run using the . command, unset the variables we used
#  
CLIENT_ID=
CLIENT_SECRET=
SHARD=

These challenges are standard for shell scripting and there are a variety of different ways to cater for the need for using spaces, single quotes and double quotes passed into commands. The next example shows later examples have been set up to work.

Example: demo3.sh


#!/bin/sh
#
# demonstration script 3 (not supported)
# 
# Using the curl command to generate an access token
# setting some shell variables to pass into the command
# using a line break option and spacing to avoid screen wrapping and aid readability
# This example sets up variables to be used by curl and allowing for
# variables within variables to be set without needing to cope with 
# single quote escaping. 
#
#  Set the shell variables
#
CLIENT_ID=f41e276e878f1960e775527beaaa64decfb0eb86207a3e08832a8f66874aa2c9
CLIENT_SECRET=f58ef564938e5fb976f31b6be8ed660cbee0f376faae66e8406c959aba0d5b8d
SHARD=us

# Temporary variables used in the curl command
AUTHORIZATION="Authorization: client_id:${CLIENT_ID}, client_secret:${CLIENT_SECRET}"
CONTENT_TYPE="Content-Type: application/json"
PAYLOAD="{\"grant_type\":\"client_credentials\"}"

curl \
	-s \
	-X POST \
	-H "${AUTHORIZATION}" \
	-H "${CONTENT_TYPE}" \
	-d "${PAYLOAD}" \
	https://api.${SHARD}.onelogin.com/auth/oauth2/v2/token

#
# For security, in case this script is run using the . command, unset the variables we used
#  
CLIENT_ID=
CLIENT_SECRET=
SHARD=
AUTHORIZATION=
CONTENT_TYPE=
PAYLOAD=

Now, we convert the test script into something that may be re-used and avoid the hard-coded parameters.

Example: demo4.sh

#!/bin/sh
#
# demonstration script 4 (not supported)
# 
# Using the curl command to generate an access token
# setting some shell variables to pass into the command
# using a line break option and spacing to avoid screen wrapping and aid readability
# This example sets up variables to be used by curl and allowing for
# variables within variables to be set without needing to cope with 
# single quote escaping. 
#
# This script shows example scripting for interactive use, passing variables into the
# script 
#
print_syntax() {
	echo "Usage: $0 <PARAMETERS>"
	echo "          -s <CLIENT_SECRET>"
	echo "          -i <CLIENT_ID>"
	echo "          -S <SHARD>"
}

#
# read command line arguments 
#
while getopts "i:s:S:" a
do
  case $a in
    	i)
      		CLIENT_ID=$OPTARG
      		;;
    	s)
      		CLIENT_SECRET=$OPTARG
      		;;
	S)
		SHARD=$OPTARG
		;;
    	?)
		print_syntax
		exit 0
      		;;
  esac
done

# Temporary variables used in the curl command
AUTHORIZATION="Authorization: client_id:${CLIENT_ID}, client_secret:${CLIENT_SECRET}"
CONTENT_TYPE="Content-Type: application/json"
PAYLOAD="{\"grant_type\":\"client_credentials\"}"

curl \
	-s \
	-X POST \
	-H "${AUTHORIZATION}" \
	-H "${CONTENT_TYPE}" \
	-d "${PAYLOAD}" \
	https://api.${SHARD}.onelogin.com/auth/oauth2/v2/token

#
# For security, in case this script is run using the . command, unset the variables we used
#  
AUTHORIZATION=
CONTENT_TYPE=
PAYLOAD=

Result breakdown

The result of the command should be a JSON string, whether the API call was successful or failed. An example of a successful result is this:

Raw JSON Success Result

{"access_token":"58dcd87b8fe7d4704ef27359a05d18271053dbd33ccfacdca29a5cb18bc72190","created_at":"2018-08-24T22:16:49.617Z","expires_in":36000,"refresh_token":"738e673cb12792bdd5a47204096232ca3328311876354c9a5be21be2c4f6e5d1","token_type":"bearer","account_id":106092}

A failure (provided it reached OneLogin to supply a fail message) might look like this:

Raw JSON Fail Result

{"status":{"error":true,"code":401,"type":"Unauthorized","message":"Authentication Failure"}}

If you are passing the result into a program which needs JSON input then this result is enough, however when working interactively it might be a good idea to reformat the output to make it more readable. This will depend on whatever add-on resource might be available. On an Apple Mac you should find that there is a pre-supplied Python module but if none are available a basic awk command will also work. Here are some examples:

Python JSON module

JSON Result Displayed with Python


$ sh demo3.sh  | python -m json.tool
{
    "access_token": "58dcd87b8fe7d4704ef27359a05d18271053dbd33ccfacdca29a5cb18bc72190",
    "account_id": 106092,
    "created_at": "2018-08-24T22:16:49.617Z",
    "expires_in": 36000,
    "refresh_token": "738e673cb12792bdd5a47204096232ca3328311876354c9a5be21be2c4f6e5d1",
    "token_type": "bearer"
}
$

Formatting with awk

If we can be sure that a comma ‘,’ is not going to be in any of the data value we can do a simple formatting using awk:

JSON Result Displayed with awk


$  sh demo3.sh | awk 'BEGIN { RS = "," } { print $0 }'
{"access_token":"58dcd87b8fe7d4704ef27359a05d18271053dbd33ccfacdca29a5cb18bc72190"
"created_at":"2018-08-24T22:16:49.617Z"
"expires_in":36000
"refresh_token":"738e673cb12792bdd5a47204096232ca3328311876354c9a5be21be2c4f6e5d1"
"token_type":"bearer"
"account_id":106092}
$

##Getting the access token If the command succeeds, then it is very likely that we want to extract the access token and use it. The other data is valuable and will be used in later examples. If the result we get back from the command is this;

Access Token JSON Data Breakdown


{
    "access_token": "58dcd87b8fe7d4704ef27359a05d18271053dbd33ccfacdca29a5cb18bc72190",
    "account_id": 106092,
    "created_at": "2018-08-24T22:16:49.617Z",
    "expires_in": 36000,
    "refresh_token": "738e673cb12792bdd5a47204096232ca3328311876354c9a5be21be2c4f6e5d1",
    "token_type": "bearer"
}

Then the value we want to us is

Access Token

58dcd87b8fe7d4704ef27359a05d18271053dbd33ccfacdca29a5cb18bc72190

Here is an example using awk where we extract the value

Scripted Access Token Extraction


$  sh demo3.sh | awk 'BEGIN { RS = "," } { print $0 }' | grep access_token | awk -F\" '{print $4 }'
58dcd87b8fe7d4704ef27359a05d18271053dbd33ccfacdca29a5cb18bc72190
$

If the API call succeeded then it prints just the access token value, if the API commend generated any error then no output is generated. In subsequent examples we will assume that an access token has been generated and stored in a shell script variable called ACCESSTOKEN, for example:

Setting an Access Token Shell Variable


$ ACCESSTOKEN=sh demo3.sh | awk 'BEGIN { RS = "," } { print $0 }' | grep access_token | awk -F\" '{print $4 }'
$ echo $ACCESSTOKEN
58dcd87b8fe7d4704ef27359a05d18271053dbd33ccfacdca29a5cb18bc72190
$

Expiration and refresh

Now, we can look at some of the other data in the JSON string. Firstly, the token can only be used for a finite amount of time. After that any use of it will generate an error. So let’s look at the full details returned:

Access Token JSON Breakdown


{
    "access_token": "58dcd87b8fe7d4704ef27359a05d18271053dbd33ccfacdca29a5cb18bc72190",
    "account_id": 106092,
    "created_at": "2018-08-24T22:16:49.617Z",
    "expires_in": 36000,
    "refresh_token": "738e673cb12792bdd5a47204096232ca3328311876354c9a5be21be2c4f6e5d1",
    "token_type": "bearer"
}

We can see when the token was created (his timestamp has a timezone of ‘Z’ for Zulu time which is GMT0) and that it may be used for 3600 second (or one hour) and so after 2018-08-24T23:16:49 Zulu it may not be used and will generate an error. If you are only doing some small query, then you can ignore all these things but if you are integrating this into some bigger solution then you may need to think about what happens after one hour. You have two alternatives

  1. Generate a brand-new access token supplying client ID and client secret using the steps described above.
  2. Use the refresh token that we will demonstrate below.
As a minor extra for shell scripting, we can use the earlier techniques to get te extra data from the JSON string. Just consider this example:

Example: demo5.sh


#!/bin/sh
#
# demonstration script 5 (not supported)
# 
# extract all the entries from a valid access token request as variables

# get the JSON data
#
JSONSTRING=sh demo3.sh
echo ${JSONSTRING}

#
# Extract various items form the JSON data
#
ACCESSTOKEN=echo ${JSONSTRING} | awk 'BEGIN { RS = "," } { print $0 }' | grep access_token | awk -F\" '{print $4 }'
REFRESHTOKEN=echo ${JSONSTRING} | awk 'BEGIN { RS = "," } { print $0 }' | grep refresh_token | awk -F\" '{print $4 }'
CREATED=echo ${JSONSTRING} | awk 'BEGIN { RS = "," } { print $0 }' | grep created_at | awk -F\" '{print $4 }'
EXPIRES=echo ${JSONSTRING} | awk 'BEGIN { RS = "," } { print $0 }' | grep expires_in | awk -F: '{print $2 }'

#
#  echo some results to confirm the details
#
echo "Access token = ${ACCESSTOKEN}"
echo "Refresh token = ${REFRESHTOKEN}"
echo "Create date (GMT0) = ${CREATED}"
echo "Expiration = ${EXPIRES}"

Now as it runs:

Example: demo5.sh Sample Run


sh demo5.sh 
{"access_token":"76a4288094950661901baa43eb61a2ca14d6e23ed3a09d0e80e56be9fa6c8174","created_at":"2018-08-26T02:46:53.276Z","expires_in":36000,"refresh_token":"29aaf32e34b3024d48144d0ffd7a8f3d6903fc8386da73900e492104cb780cf8","token_type":"bearer","account_id":106092}
Access token = 76a4288094950661901baa43eb61a2ca14d6e23ed3a09d0e80e56be9fa6c8174
Refresh token = 29aaf32e34b3024d48144d0ffd7a8f3d6903fc8386da73900e492104cb780cf8
Create date (GMT0) = 2018-08-26T02:46:53.276Z
Expiration = 36000
$

NOTE: The expires_in result is not a string so the shell command to extract it is slightly different.

Refreshing an access token

Now we can see how to get at the refresh token we can also run a command that uses it. In this example we will pass in the access token, refresh token and optionally the shard (where e will default to ‘us’ if not specified.

Example: demo6.sh


#!/bin/sh
#
# demonstration script 6 (not supported)
# 
# Using the curl command to generate a new access token
# supplying an existing access token and its refresh token
#
print_syntax() {
	echo "Usage: $0 "
	echo "          -a "
	echo "          -r "
	echo "          -S "
}

#
# set a default shard
SHARD=us

#
# read command line arguments 
#
while getopts "a:r:S:" a
do
  case $a in
    	a)
      		ACCESSTOKEN=$OPTARG
      		;;
    	r)
      		REFRESHTOKEN=$OPTARG
      		;;
	    S)
		      SHARD=$OPTARG
		      ;;
    	?)
		      print_syntax
		      exit 0
      		;;
  esac
done

# Temporary vatiables used in the curl command
CONTENT_TYPE="Content-Type: application/json"
PAYLOAD="{\"grant_type\":\"refresh_token\",\"access_token\":\"${ACCESSTOKEN}\",\"refresh_token\":\"${REFRESHTOKEN}\"}"

curl \
	-s \
	-X POST \
	-H "${CONTENT_TYPE}" \
	-d "${PAYLOAD}" \
	https://api.${SHARD}.onelogin.com/auth/oauth2/v2/token

#
# For security, in case this script is run using the . command, unset the variables we used
#  
CONTENT_TYPE=
PAYLOAD=

So now we run it:

Example: demo6.sh Sample Run


$ sh demo6.sh -a 76a4288094950661901baa43eb61a2ca14d6e23ed3a09d0e80e56be9fa6c8174 -r 29aaf32e34b3024d48144d0ffd7a8f3d6903fc8386da73900e492104cb780cf8
{"access_token":"76a4288094950661901baa43eb61a2ca14d6e23ed3a09d0e80e56be9fa6c8174","created_at":"2018-08-26T02:46:53.276Z","expires_in":36000,"refresh_token":"29aaf32e34b3024d48144d0ffd7a8f3d6903fc8386da73900e492104cb780cf8","token_type":"bearer","account_id":106092}
$

At the time of writing the refresh token is valid for 45 days after creation but check documentation for any changes at https://developers.onelogin.com/api-docs/1/oauth20-tokens/refresh-tokens-2

Rate limits

There is a global setting for each OneLogin account which limits the number of API calls that can be made per hour. This is for your entire OneLogin account and not just the one access token that you create, or pair of API credentials used. At any time, you can check to see how many calls may be made and using your current access token as the single variable in the call. Here is an example where the access token gets passed in as the variable.

Example: demo7.sh

#!/bin/sh
#
# demonstration script 7 (not supported)
# 
# Using the curl command to check on the current APU usage
# for the account
#
print_syntax() {
	echo "Usage: $0 "
	echo "          -a "
	echo "          -S "
}

#
# set a default shard
SHARD=us

#
# read command line arguments 
#
while getopts "a:S:" a
do
  case $a in
    	a)
      		ACCESSTOKEN=$OPTARG
      		;;
	    S)
		      SHARD=$OPTARG
		      ;;
    	?)
		      print_syntax
		      exit 0
      		;;
  esac
done

# Temporary vatiables used in the curl command
AUTHORIZATION="Authorization: bearer:${ACCESSTOKEN}"

curl \
	-s \
	-X GET \
	-H "${AUTHORIZATION}" \
	https://api.${SHARD}.onelogin.com/auth/rate_limit

#
# For security, in case this script is run using the . command, unset the variables we used
#  
AUTHORIZATION=
SHARD=

So, when we run it:

Example: demo7.sh Sample Run Raw Output


$ sh demo7.sh -a 76a4288094950661901baa43eb61a2ca14d6e23ed3a09d0e80e56be9fa6c8174

{"status":{"error":false,"code":200,"type":"success","message":"Success"},"data":{"X-RateLimit-Limit":5000,"X-RateLimit-Remaining":5000,"X-RateLimit-Reset":3600}} $

Or, with a bit of formatting to make it readable:

Example: demo7.sh Sample Run with Formatted Output


$ sh demo7.sh -a 76a4288094950661901baa43eb61a2ca14d6e23ed3a09d0e80e56be9fa6c8174 | python -m json.tool
{
     "data": {
          "X-RateLimit-Limit": 5000,
          "X-RateLimit-Remaining": 5000,
          "X-RateLimit-Reset": 3600
     },
     "status": {
          "code": 200,
          "error": false,
          "message": "Success",
          "type": "success"
     }
}
$

This show a token which has not been used as the full allowance of API calls is available – lets look at a result where the access token has been used for a number of API calls

Example: demo7.sh Second Sample Run

$ sh demo7.sh -a 76a4288094950661901baa43eb61a2ca14d6e23ed3a09d0e80e56be9fa6c8174 | python -m json.tool
{
    "data": {
        "X-RateLimit-Limit": 5000,
        "X-RateLimit-Remaining": 4996,
        "X-RateLimit-Reset": 3584
    },
    "status": {
        "code": 200,
        "error": false,
        "message": "Success",
        "type": "success"
    }
}
$

Notice the remaining calls available is 4996 as 4 API calls were made using the token