Usage

API Key

The API key is a cryptographically strong random sequence of numbers hashed into a 128-character string. It is encrypted and stored internally using AES 256 encryption. Any language with a Representational State Transfer (REST) compliant interface can access the API with the API key and RunAs in the authorization header.

Some environments may still use an old-style API key, which is a formatted Globally Unique Identifier (GUID). Rotating the API Key produces the new-style API key described above.

Session State

Session state is maintained between API calls. The method is dependent on the scripting language. Initiate a session using API POST Auth/SignAppIn and always call POST Auth/Signout when you are done.

Base Endpoint

The following base endpoint is used throughout this document. the-server is a placeholder and should be replaced with the server name in your environment. SSL is required to use the Password Safe Public API.

<base> = https://the-server/BeyondTrust/api/public/v3

 

The base endpoint has changed as of v6.2.0. The previous endpoint (https://the-server/eEye.RetinaCS.Server/api/public/v3) will continue to accept API calls, however new scripts should use the new endpoint above and existing scripts should be changed at the earliest opportunity after upgrading to v6.2.0 (or above). This change decouples the API from BeyondInsight and Password Safe, isolating resources and allowing standalone API configuration.

Authorization Header

Use the web request authorization header to communicate the API application key, the RunAs username, and the user password:

  • key: The API key configured in BeyondInsight for your application.
  • runas: The username of a BeyondInsight user that has been granted permission to use the API key.
  • pwd: The RunAs user password surrounded by square brackets (optional; required only if the User Password is required on the application API registration).
Authorization=PS-Auth key=c479a66f…c9484d; runas=doe-main\johndoe; pwd=[un1qu3];

The API keys in the examples have been shortened for brevity. A domain user is being used.

Two-Factor Authentication

Depending on how the two-factor server is configured, a programmatic two-factor challenge is sometimes required.

No Challenge

If the two-factor server is configured to authenticate through a push or mobile two-factor challenge, a challenge response is often not required. The first call to POST Auth/SignAppIn logs the user in, as long as the authentication request to the two-factor server does not time out.

Challenge

When a two-factor challenge is configured, two calls to POST Auth/SignAppIn are required and session state must be maintained between these two calls to validate the two-factor challenge.

The initial call to POST Auth/SignAppIn results in a 401 Unauthorized response which contains a header WWW-Authenticate-2FA containing the prompt from the authentication service. The prompt can be used to prompt the user for the challenge answer.

If the WWW-Authenticate-2FA header is not present, a two-factor authentication challenge has not been configured for the user.

When the challenge answer has been received from the user, POST Auth/SignAppIn is called again with the challenge answer in the authorization header, similar to the other authorization parameters:

  • challenge: The answer to the two-factor challenge.
Authorization=PS-Auth key=c479a66f…c9484d; runas=doe-main\johndoe; pwd=[un1qu3]; challenge=543687;

The challenge answer is only required on the second call to POST Auth/SignAppIn and not on subsequent requests.

OAuth Public API Authentication

The OAuth sign-in method uses the OAuth client credential flow. The client credentials grant type is used by clients to obtain an access token outside of the context of a user.

Only users with user type Application, who are associated to an API Access Policy API registration in BeyondInsight, can use this authentication method.

Impersonation for the OAuth client credential flow is different than API key. Instead of providing the RunAs user as part of the Authorization header you provide the RunAs user using a new RunAs header. You can only impersonate users who are in the same group as the application user.

Setting up an OAuth authentication method requires the following steps:
  • Create an API Registration using the API Access Policy type
  • Create an application user
  • Assign your access policy to the user
  • Record their client ID and secret for later use
  • Assign user to a group with necessary permissions

For more information, please see OAuth 2.0 Client Credentials Grant.

Common Response Codes

Below are response codes common to all APIs. Custom responses are detailed in the individual endpoints.

  • 200 – Request successful.
  • 204 – Request successful. No content in body.
  • 400 – Bad Request – Validation failure, missing request body, or string values exceed the maximum length. Reason in response body.
  • 401 – Unauthorized – User is not authenticated. Typical reasons include:
    • An invalid product license was detected.
    • The request headers were not set properly.
    • The server could not verify the validity of the request (due to one or more API factors).
    • The user session has expired.
    • The API key has been rotated but has not been updated in the calling script or application.

When you encounter a 401 error due to factor validation failure, a User Audit entry is created in BeyondInsight and an email is sent to the administrator detailing the reason. Look here first for the reason why authorization failed.

  • 403: – Access forbidden. User does not have the appropriate role or permission.

A 403 can also occur when SSL trust cannot be established.

  • 404 – Object not found where expected. Reason in response body.
  • 500 – Unexpected server error occurred. Please contact the developers.

Examples

C#

Create and reuse a persistent connection using the System.Net.Http.HttpClient class.

HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization",
"PS-Auth key= c479a66f…c9484d; runas=doe-main\johndoe;");

string json = Newtonsoft.Json.JsonConvert.SerializeObject(null);
System.Net.Http.StringContent content = new StringContent(json);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

HttpResponseMessage signInResponse = client.PostAsync("<base>/Auth/SignAppin", content).Result;

Subsequent calls:

HttpResponseMessage getResponse = client.GetAsync("<base>/ManagedAccounts").Result;

User Password Factor Enabled (header example only)

HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization",
"PS-Auth key= c479a66f…c9484d; runas=doe-main\johndoe; pwd=[un1qu3];");
Powershell

Powershell internally creates a session variable to use for each subsequent call; Invoke-RestMethod CmdLet options -SessionVariable and -WebSession respectively. In the below example, the variable is named "session" and has script-level scope.

$headers = @{ Authorization="PS-Auth key=c479a66f…c9484d; runas=doe-main\johndoe;"; };
$uri = "<base>/Auth/SignAppin";
$signinResult = Invoke-RestMethod -Uri $uri -Method POST -Headers $headers -SessionVariable script:session;

Subsequent calls:

$uri = "<base>/ManagedAccounts";
$accounts = Invoke-RestMethod -Uri $uri -Method GET -WebSession $script:session -Headers $headers;
Java

Create and reuse a persistent connection using the java.net.HttpURLConnection class.

URL baseURL = new URL("HTTPS", "the-server", 443, "/BeyondTrust/api/public/v3/");
URL url = new URL(baseURL, "Auth/SignAppIn");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestProperty("Authorization","PS-Auth key=c479a66f…c9484d; runas=doe-main\johndoe;");
Ruby

Using the rest-client gem, carry over the ASP.NET_SessionId header.

samp_key = 'PS-Auth key= c479a66f…c9484d; runas=doe-main\johndoe;'
result = RestClient::Request.execute(method: :post, url: '<base>/Auth/SignAppin', :headers => {‘Authorization’ => samp_key} )
session_id = result.cookies["ASP.NET_SessionId"]

Subsequent calls:

result = RestClient::Request.execute(method: :get, url: '<base>/ManagedAccounts', :headers=>{‘Authorization’ => samp_key, :cookies => {'ASP.NET_SessionId' => session_id}} )
Python

Create and reuse a persistent connection using the requests module.

header = {'Authorization': 'PS-Auth key=c479a66f…c9484d; runas=doe-main\johndoe;'}
session = requests.Session()
session.headers.update(header)
response = session.post('<base>/Auth/SignAppin')

Subsequent calls:

accounts = session.get('<base>/ManagedAccounts')
Bash

Using curl, option –c will create cookie file and –b will use it in subsequent API calls.

curl -i -c pbpscookie.txt -X POST https:<base>/Auth/SignAppin -H "Content-Type: application/json" -H "Authorization: PS-Auth key=c479a66f…c9484d; runas=doe-main\johndoe;" -d ""

Subsequent calls:

curl -i -b pbpscookie.txt -X GET https:<base>/ManagedAccounts -H "Content-Type: application/json" -H "Authorization: PS-Auth key=c479a66f…c9484d; runas=doe-main\johndoe;" -d ""

Workflow

There are some loose dependencies between the APIs. A typical sequence is to list accounts or find an account, request a password, retrieve that password (once approved), and then release the password.

Create and Manage an Asset, Create User Group, Assign Roles

Case: Create and manage an asset, create a managed account, create a managed account quick rule, create/provision an LDAP/AD/BeyondInsight user group, grant Read access to new Smart Rule with requester role and access policy.

  • POST <base>/Auth/SignAppin
  • POST <base>/Workgroups/{ID}/Assets
  • POST <base>/Assets/{assetId}/ManagedSystems
  • POST <base>/ManagedSystems/{managedSystemId}/ManagedAccounts
  • POST <base>/QuickRules
  • POST <base>/UserGroups
  • POST <base>/UserGroups/{userGroupId}/SmartRules/{smartRuleId}/Roles
  • POST <base>/Auth/Signout

Retrieve a Password

Case: request, retrieve, and check in a password for a managed account:

  • POST <base>/Auth/SignAppin
  • GET <base>/ManagedAccounts OR GET <base>/ManagedAccounts?systemName={systemName}&accountName={accountName}
  • POST <base>/Requests
  • GET <base>/Credentials/{requestId}
  • PUT <base>/Requests/{requestId}/Checkin
  • POST <base>/Auth/Signout

Create a Session

Case: request a session, create a session, and check in the request for a managed account:

  • POST <base>/Auth/SignAppin
  • GET <base>/ManagedAccounts OR GET <base>/ManagedAccounts?systemName={systemName}&accountName={accountName}
  • POST <base>/Requests (AccessType="RDP" or AccessType="SSH" or AccessType="App")
  • POST <base>/Requests/{requestId}/Sessions (SessionType == Request.AccessType above)
  • PUT <base>/Requests/{requestId}/Checkin
  • POST <base>/Auth/Signout

Retrieve a Password as an ISA

Case: create an ISA password request:

  • POST <base>/Auth/SignAppin
  • GET <base>/ManagedAccounts OR GET <base>/ManagedAccounts?systemName={systemName}&accountName={accountName}
  • POST <base>/ISARequests
  • POST <base>/Auth/Signout

Create a Session as an ISA

Case: create an ISA session:

  • POST <base>/Auth/SignAppin
  • GET <base>/ManagedAccounts OR GET <base>/ManagedAccounts?systemName={systemName}&accountName={accountName}
  • POST <base>/ISASessions
  • POST <base>/Auth/Signout