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.
- OpenID Connect Opens the Door to SAS Viya APIs
- Authentication to SAS Viya: a couple of approaches
- Building custom apps on top of SAS Viya
- SAS Viya end-to-end use case authentication
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.
- Developers contact the organization's SAS administrator to register a client application.
- The SAS administrator registers the client and provides a client id and secret.
- 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.
- 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.
- Select Configuration on the main SAS Environment Manager page.
- Select Definitions from the View menu on the Configuration page.
- Select
sas.commons.web.security.cors
from the list of configuration definitions. - Click the New Configuration button if you are setting the CORS options for the first time.
- Or click the pencil icon to edit an existing CORS definition.
- Make sure
allowCredentials
is enabled. Set theallowHeaders
andallowMethods
properties to * (or wildcard) to accept all values. - For and
allowOrigins
, specify a comma-separated list of values for each client that is enabled by default in cross-origin requests. - 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.