Getting Started

Introduction

SAS Viya REST APIs are based on resource-oriented URLs, use HTTP authentication and HTTP verbs, and return HTTP response codes to indicate API errors. With SAS Viya REST APIs, you can create and access SAS resources using any client technology.

The following documentation covers how to register clients, create access tokens, and make basic API calls. You’ll also find guidelines on collections, links, pagination, filtering, and other general usage information on SAS Viya REST APIs. More detailed information is available in the following resources, most of which are referenced in the sections below.


Authentication to SAS Viya

SAS Viya provides authentication services with the SAS Logon Manager. These services are built around Open Authorization (OAuth) and OpenID Connect. SAS Logon Manager uses OAuth policy to enforce the access token to allow access to APIs and protected resources. SAS Viya integrates with the identity management system that your organization uses.

The steps below outline the process of obtaining an access token.

  1. Developers contact the organization's SAS administrator to register a client application.
  2. The SAS administrator registers the client and provides a client id and secret.
  3. Developers implement code to acquire the token used for API calls. The request for the token must include the registered client id and client secret.
  4. The resulting access token is passed on API calls.

Note: The examples below are not exhaustive for languages or grant types. Please refer to SAS Viya end-to-end use case authentication for additional sample code.


Steps for SAS Administrator

All applications and scripts that make use of the SAS Viya REST APIs must be registered with the SAS environment.

Register the client

A SAS administrator uses the SAS Logon OAuth API to configure a client with the OAuth service in SAS Logon Manager using the following steps.

Get access token for client registration

A user in the SAS Administrators group makes and API call to SAS Logon to generate an access token, which will in turn be used to register a client (application). Below is an example of the command where the resulting token is stored in the BEARER_TOKEN variable.

Request client registration OAuth token using password

For example, to register a client named myclientid, issue the following command:

curl

export BEARER_TOKEN=`curl -sk -X POST "https://<sas-server>/SASLogon/oauth/token" \
  -u "sas.cli:"
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&username=user&password=password"`

Python

import requests
url="https://<sas-server>/SASLogon/oauth/token"
payload=grant_type=password&username=username&password=password
headers={
'Content-Type':'application/x-www-form-urlencoded',
'Authorization':'Basic c2FzLmNsaTo='}

response= requests.request("POST", url, headers=headers, data=payload)
bearer_token= json.loads(response.text)['access_token']
Request client registration OAuth token using browser and credentials

Place the following URL in a browser.

https://<sas-server>/SASLogon/oauth/authorize?client_id=sas.cli&response_type=token

If presented with the SAS login screen, log in with your credentials. Once logged in, notice the very long URL in the address bar. It should have a form similar to the following.

https://<sas-server>/SASLogon/out_of_band#token_type=bearer&access_token=eyJhbGciOiJSUzI.....5ag2sumb9A&expires_in=3599&scope=.....

This string contains, among other things an access token. Paste the URL to an editor and then copy the contents between access_token= and &expires (that's the access_token).

Now let's put the access token into a variable with the following command.

export BEARER_TOKEN=eyJhbGciOiJSUzI.....5ag2sumb9A
Grant types

A grant is a method of acquiring an access token. Deciding which grants to implement depends on the type of client the end user will be using. SAS supports three grant types (not including refresh_token, which is covered later). These include authorization_code, client_credentials, and password. Each grant is described in the table below.

authorized_grant_type Description
authorization_code User-centric grant flow – facilitates the client obtaining an access token without ever handling the user's credentials
client_credentials Group-based grant flow – based on SAS Viya custom group-based access
password Not for use outside of test or dev instances. Easiest to configure, but is the least secure grant type

Choosing the proper grant type depends on your environment and configuraiton. This choice plays out in client registration and access token requests. For detailed information, see this article on choosing an OAuth flow for SAS Viya.

Client registration

Use the value of access_token returned in the response JSON from the earlier section to register the new client.

The following sections outline the code required to register the client, listed by grant type. Parameters for each grant type are defined in the following table.

Query parameter Parameter Value Required Description
Authorization Bearer eyJhbGciOiJSUzI1NiIsI... Yes access token returned in the response from the previous step
client_id app yes name of the client to register; this must match the serviceId from the previous step
client_secret secret Yes secret string used for authenticating as the client; assigned by the admin registering the client
scope openid Yes in most instances scope should always include "openid"; for more information on scope, see this thread
authorized_grant_types authorization_code, client_credentials, or password Yes method of acquiring an access token
authorities <group name(s)> client_credentials specifies the groups tokens get using the client_credentials grant_type; for more information on authorities, see this thread
redirect_uri urn:ietf:wg:oauth:2.0:oob authorization_code allowed URI pattern for redirect during authorization
access_token_validity 35999 (default) No Controls access token ttl; default is 10 hours; can be set to any number of seconds
Scopes and Authorities

The changes for scopes and authorities attributes in client registration now closely align with OpenID Connect standards.

Scopes

The list of scopes allows for the client to obtain on behalf of users, when using any grant type other than “client_credentials”. For most SAS Viya APIs, “openid” is sufficient. Previously, SAS user groups were listed under scopes. Now, user groups are handled under the authorities parameter. Please note however, that the SASAdministrators group is still handled under scopes. This was done so that a user must opt-in to SASAdministrators when getting an authorization code.

For client applications that only use the grant type “client_credentials” and therefore do not act on behalf of users, use the default scope “uaa.none”.

Grant Type Recommended Values
authorization_code openid (SASAdministrators in some cases)
client_credentials uaa.none
password openid, (SASAdministrators in some cases)
Authorities

For use with "client credentials" grant type. Authorities specify the SAS groups the tokens inherit. For “authorization_code” and “password” grants, all SAS user groups are assumed and included. You do not pass the authorities attribute when using authorization_code or password grant types.

Grant Type Recommended Values
client_credentials Explicit SAS user groups
Authorization Code

Use the following code to register a client using the authorization_code grant type:

curl

curl -k -X POST "https://<sas-server>/SASLogon/oauth/clients" \
   -H "Content-Type: application/json" \
   -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsIm..." \
   -d '{"client_id": "myclientid",
     "client_secret": "myclientsecret",
     "scope": ["openid"],
     "authorized_grant_types": ["authorization_code","refresh_token"],>
     "redirect_uri": "urn:ietf:wg:oauth:2.0:oob"}'

Python

import requests
url = "https://<sas-server>/SASLogon/oauth/clients"
payload = '{"client_id": "myclientid", "client_secret": "myclientsecret", "scope": ["openid"], "authorized_grant_types": ["authorization_code", "refresh_token"], "redirect_uri": "urn:ietf:wg:oauth:2.0:oob"}'
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer eyJhbGciOiJSUzI1...'}

response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)

Response

{
  "scope": ["openid"],
  "client_id": "myclientid",
  "resource_ids": ["none"],
  "authorized_grant_types": ["authorization_code", "refresh_token"],
  "redirect_uri": ["urn:ietf:wg:oauth:2.0:oob"],
  "autoapprove": [],
  "authorities": ["uaa.none"],
  "lastModified": 1547138692523,
  "required_user_groups": []
}
Client Credentials

Use the following code to register a client using the client_credentials grant type:

curl

 curl -k -X POST "https://<sas-server>/SASLogon/oauth/clients" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsIm..." \
    -d '{"client_id": "myclientid",
      "client_secret": "myclientsecret",
      "authorized_grant_types": "client_credentials",
      "authorities": "<CUSTOM_GROUP>",
      "scope": ["uaa.none"]}'

Python

import requests
url = "https://<sas-server>/SASLogon/oauth/clients"
payload='{"client_id": "myclientid", "client_secret": "myclientsecret", "authorized_grant_types": "client_credentials", "scope": "uaa.none *", "authorities": "<CUSTOM_GROUP>"}'
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer eyJhbGciOiJSUzI1...'}

response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)

Response

{"scope":["uaa.none"],"client_id":"myclient_id","resource_ids":["none"],"authorized_grant_types":["client_credentials"],"autoapprove":[],"authorities":["<CUSTOM_GROUP>"],"lastModified":1626724462841,"required_user_groups":[]}`
Password

Use the following code, to register a client using the password grant type:

curl

curl -k -X POST "https://<sas-server>/SASLogon/oauth/clients" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsIm..." \
    -d '{"client_id": "myclientid",
      "client_secret": "myclientsecret",
      "scope": ["openid"],
      "authorized_grant_types": ["password","refresh_token"]}'

Python

import requests
url = "https://<sas-server>/SASLogon/oauth/clients"
payload='{"client_id": "myclientid", "client_secret": "myclientsecret", "authorized_grant_types": "password", "scope": ["openid"]}'
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer eyJhbGciOiJSUzI1...'}

response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)

Response

{
  "scope": ["openid"],
  "client_id": "myclientid",
  "resource_ids": ["none"],
  "authorized_grant_types": ["password", "refresh_token"],
  "redirect_uri": ["urn:ietf:wg:oauth:2.0:oob"],
  "autoapprove": [],
  "authorities": ["uaa.none"],
  "lastModified": 1547138692523,
  "required_user_groups": []
}

Once the client is registered, the SAS administrator provides the client identifier and client secret to the developer/user.

Setting Cross-Origin Resource Sharing (CORS) Options

If you are developing a web application using SAS Viya REST APIs, you need your SAS administrator to configure CORS settings on the SAS servers. Cross-origin resource sharing is a W3C specification supported by most browsers to allow you to specify how cross domain requests are authorized.

More Information on CORS

SAS Viya servers can provide support for Cross-Origin Resource Sharing (CORS), a technique enables Javascript on a web page to consume a REST API served from a different origin. CORS is implemented when a server is configured to include additional HTTP headers to let a user agent access selected resources from a server on a different origin (or domain) than the site currently in use. A user agent makes a cross-origin HTTP request when it requests a resource from a different domain, protocol, or port than the one from which the current document originated.

In the simplest scenario, cross-origin communications starts with a client making a GET, POST, or HEAD request against a resource endpoint on the server. The request includes an Origin header that indicates the origin of the client code. The server considers the request's Origin and either allows or disallows the request. If the server allows the request, then it responds with the requested resource and an Access-Control-Allow-Origin header in the response. This header indicates to the client which client origins should be permitted to access the resource. Assuming that the Access-Control-Allow-Origin header matches the request's Origin, the browser allows the request.

If Access-Control-Allow-Origin is missing in the response or if its value does not match the request's Origin, the browser disallows the request.

If you want to enable developers to utilize SAS Viya REST APIs in web applications, you must enable CORS support in the SAS Viya environment using SAS Environment Manager. To configure or update the setting:

Log into SAS Environment Manager and assume administrator privileges. Note that you must have an account that is authorized as a SAS Administrator to perform these actions.

  1. Select Configuration on the main SAS Environment Manager page.
  2. Select Definitions from the View menu on the Configuration page.
  3. Select sas.commons.web.security.cors from the list of configuration definitions.
  4. Click the New Configuration button if you are setting the CORS options for the first time.
  5. Or click the pencil icon to edit an existing CORS definition.
  6. Make sure allowCredentials is enabled. Set the allowHeaders and allowMethods properties to * (or wildcard) to accept all values.
  7. For and allowOrigins, specify a comma-separated list of values for each client that is enabled by default in cross-origin requests.
  8. Click Save to complete the configuration.

That's it. The CORS setting is in effect for all services supporting the SAS Viya REST APIs.


Steps for Developers

Contact the SAS Administrator to get a registered client id and the client secret (steps outlined in previous section).

Registered clients request an access token using the SAS Logon OAuth API token endpoint and passing the grant_type used in client registration.

Generate access token

Depending on the grant_type, use the following procedures to obtain an access token.

Authorization code

To get the access token using the authorization code grant type for the myclientid client, first place the following URL in a browser (be sure to replace hostname and clientid accordingly):
https://<sasserver>/SASLogon/oauth/authorize?client_id=myclientid&response_type=code

A SAS Viya log in screen appears. Enter valid SAS credentials. You are presented with a list of scopes. Select access as appropriate for the client and then click the Authorize Access button. An Authorization code is presented (YZuKQUg10Z for example). The authorization code is valid for use one time. Copy the code value for use in the next step.

Next, using the authorization code, send the following command to get the access token, specifying parameters from the table below:

Query parameter Description
-d grant_type, code authorization_code grant type and authorization code value
-u myclientid:myclientsecret registered clientid and secret

curl

curl -k -X POST https://<sas-server>/SASLogon/oauth/token \
   -H "Accept: application/json" \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "grant_type=authorization_code&code=YZuKQUg10Z" \
   -u "myclientid:myclientsecret"

Python

import requests
url = "https://<sas-server>/SASLogon/oauth/token#authorization_code"
payload={"client_id": "myclientid", "client_secret": "myclientsecret", "grant_type": "authorization_code", "code": "bPbbF0QU5u"}
headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'}

response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)

Response

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZ...",
  "token_type": "bearer",
  "refresh_token": "eyJhbGciOiJSUzI1NiIsImtpZC...",
  "expires_in": 3599,
  "scope": ["openid"],
  "jti": "b35f26197fa849b6a1856eea1c722933"
}
Client credentials

To get the access token using the client_credentials grant type for the app client, send the following command, specifying parameters from the table below:

Query parameter Description
-d grant_type, code client_credentials grant type
-u myclientid:myclientsecret registered clientid and secret

curl

curl -k -X POST "https://<sas-server>/SASLogon/oauth/token" \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "grant_type=client_credentials" \
   -u "myclientid:myclientsecret"

Python

import requests
url = "https://<sas-server>/SASLogon/oauth/token"
payload='{"grant_type": "client_credentials"}'
headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Basic YXBpLmNyZWRzOmFwaS5zZWNyZXQ='}

Where the Authorization key is the base64 encoded clientid:clientsecret.

response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)

Response

{"access_token":"eyJhbGciOiJSUzI1Ni...","token_type":"bearer","expires_in":3599,"scope":"uaa.none","jti":"f294c71cf6cc4a259c88880bc0b6c944"}`
Password

To get the access token using the password grant type for the user sasdemo and app client, send the following command, specifying parameters from the table below:

Query parameter Description
-d grant_type, username, password password grant type, SAS username, and password
-u myclientid:myclientsecret registered clientid and secret

curl

curl -k -X POST https://<sas-server>/SASLogon/oauth/token \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "grant_type=password&username=sasdemo&password=mypassword" \
   -u "myclientid:myclientsecret"

Python

import requests
url = "https://<sas-server>/SASLogon/oauth/token"
payload='{"grant_type": "password", "username": "username", "password": "password"}'
headers = {'Content-Type': 'application/json'}

response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)

Response

Sample response:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZ...",
  "token_type": "bearer",
  "refresh_token": "eyJhbGciOiJSUzI1NiIsImtpZC...",
  "expires_in": 3599,
  "scope": ["openid"],
  "jti": "b35f26197fa849b6a1856eea1c722933"
}
Refresh Token

To avoid the hassle of repeating the access token retrieval process, use the refresh token to get a new access token. Most applications deal with expiring and refreshing tokens programmatically.

More information on refresh tokens

The refresh token is valid for the password and authorization code grant types only. The refresh token creation is determined during the client registration process by adding it to the grant_type parameter as follows: "authorized_grant_types": ["authorization_code", "refresh_token"],

The refresh token is then returned in the subsequent access token call: {"access_token":" eyJhbGciOiJSUzI1NiIsImtpZ...", "token_type":"bearer", "refresh_token":"eyJhbGciOiJSUzI1NiIsImtpZC..."

The refresh token can be used to get a new access token using a command like the following:

curl

curl -k https://<sas-server>/SASLogon/oauth/token -H "Accept: application/json" \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -u "myclientid:myclientsecret" \
   -d "grant_type=refresh_token&refresh_token=eyJhbGciOiJSUzI1NiIsImtpZC..."

Python

import requests
url = "https://<sas-server>/SASLogon/oauth/token"
payload = "grant_type=refresh_token&refresh_token=eyJhbGciOiJSUzI1NiIsImpr......"
headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}

response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)

Response

Sample response:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZ...",
  "token_type": "bearer",
  "refresh_token": "eyJhbGciOiJSUzI1NiIsImtpZC...",
  "expires_in": 3599,
  "scope": "openid",
  "jti": "b35f26197fa849b6a1856eea1c722933"
}

Note, the access token is new, and the refresh token remains static.