Navigating through a sea of data assets can be a daunting task. SAS Information Catalog is your navigator in this journey, allowing you to discover, search, and manage your SAS Viya assets efficiently. When a data asset is discovered, hundreds of metrics are calculated. Imagine accessing these metrics with a simple command, downloading them, or even using them in a report or a flow. This blog series will guide you through the process of leveraging the SAS Information Catalog REST APIs from Python to learn more about your SAS Viya data assets. This post, in particular, will focus on acquiring an access token using a method revised in 2023.
If you're new to SAS Information Catalog, here's a quick rundown. If you prefer to watch a video, check out SAS Demo | Top Data Questions You Can Answer with SAS Information Catalog or How to Use SAS Information Catalog. If you prefer to read, the catalog:
Despite having comprehensive interfaces in SAS Information Catalog, there might be a need for custom reporting or workflows based on specific asset characteristics. SAS Information Catalog APIs, now made public, are the solution to this challenge.
Despite the availability of resources, getting a SAS Viya access token can sometimes be confusing and many users get stuck at this stage. The SAS Software GitHub page explains a simple method to get an access token to work with SAS Viya REST APIs.
However, there's a more secure and efficient method, described by Joe Furbee in Register Client and Create Access Token. I prefer this method as it excludes the password from the Python program, making the program more "Git-ready". The method also registers a client, uses an authorization code, and a TLS certificate to secure data in transit.
For a more visual understanding of the process, you can watch the following recorded demonstration:
Here’s the complete code to get an access token and a refresh token.
# Run instructions
"""
Using Joe Furbee's approach: https://github.com/sassoftware/rest-api-use-cases/blob/main/python/authentication/registerClient_generateToken_Python_2023.ipynb
https://blogs.sas.com/content/sgf/2023/02/07/authentication-to-sas-viya/
"""
print('\nGetting parameters from the command line\n')
# 1 Packages
import requests, json, os, base64, sys
# 2. Arguments
print ("Number of arguments:", len(sys.argv), "arguments\n")
#print ("Argument List:", str(sys.argv))
baseURL=str(sys.argv[1])
client_id=str(sys.argv[2])
client_secret=str(sys.argv[3])
admin_user=str(sys.argv[4])
admin_password=str(sys.argv[5])
pem_path=str(sys.argv[6])
print()
print ("\nWe are going to use a certificate: ", pem_path)
# 3. Construct Variables
authUri="/SASLogon/oauth/token"
print('\nYour SAS VIYA host is ', baseURL)
print ('\nAuth URL', authUri)
# Get a BEARER_TOKEN to delete and register a client
print('\nGet a BEARER_TOKEN to register a client\n')
# generate API call for register access token
url = f"{baseURL}/SASLogon/oauth/token"
payload = f"grant_type=password&username={admin_user}&password={admin_password}"
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic c2FzLmNsaTo='
}
# process the results
response = requests.request("POST", url, headers=headers, data=payload, verify=pem_path)
register_access_token = json.loads(response.text)['access_token']
print(json.dumps(response.json(), indent=4, sort_keys=True))
headers = {
'Content-Type': 'application/json',
'Authorization': "Bearer " + register_access_token
}
"""
# Delete the client if it already exists
print()
print(f"Delete the client {client_id} if it exists, using the BEARER_TOKEN")
print()
print(baseURL, "client", client_id)
response = requests.request("DELETE", f"{baseURL}/SASLogon/oauth/clients/{client_id}", headers=headers, verify=pem_path)
print(json.dumps(response.json(), indent=4, sort_keys=True))
"""
# Register the client using the BEARER_TOKEN
print(f"\nRegister the client {client_id} using the BEARER_TOKEN\n")
# create API call payload data
payload='{"client_id": "' + client_id +'","client_secret": "'+ client_secret +'","scope": ["openid", "uaa.user"],"authorized_grant_types": ["authorization_code","refresh_token"],"redirect_uri": "urn:ietf:wg:oauth:2.0:oob","access_token_validity": "43199"}'
# generate API call for register access token
url = f"{baseURL}/SASLogon/oauth/clients"
# REGISTER THE CLIENT process the results
response = requests.request("POST", url, headers=headers, data=payload, verify=pem_path)
print(json.dumps(response.json(), indent=4, sort_keys=True))
# Create an access token using the client and an authorization code
print('\nCreate an access token using the client and an authorization code\n')
# create the authorization url
codeURL = baseURL + "/SASLogon/oauth/authorize?client_id=" + client_id + "&response_type=code"
# encode the client string
client_string = client_id + ":" + client_secret
message_bytes = client_string.encode('ascii')
base64_bytes = base64.b64encode(message_bytes)
base64_message = base64_bytes.decode('ascii')
# prompt with instructions and entry for auth code
print(f"* Please visit the following site {codeURL}")
print("* If provided a login prompt, add your SAS login credentials")
print("* Once authenticated, you'll be redirected to an authorization screen, check all of the boxes that appear")
print("* This will result in a short string of numbers and letters such as `VAxVFVEnKr`; this is your authorization code; copy the code")
code = input("Please enter the authorization code you generated through the previous instructions, and then press Enter: ")
# generate API call for access token
url = f"{baseURL}/SASLogon/oauth/token#authorization_code"
payload = "grant_type=authorization_code&code=" + code
headers = {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': "Basic " + base64_message
}
# process the results
response = requests.request("POST", url, headers=headers, data=payload, verify=pem_path)
access_token = json.loads(response.text)['access_token']
refresh_token = json.loads(response.text)['refresh_token']
print(json.dumps(response.json(), indent=4, sort_keys=True))
# Create directory
#directory = os.getcwd()
directory = 'api'
if not os.path.exists("api/"):
os.mkdir("api/")
# Create access_token.txt file
with open(directory + '/access_token.txt', 'w') as f:
f.write(access_token)
print('\nThe access token was stored for you as ' + directory + '/access_token.txt\n')
# Create refresh_token.txt file
with open(directory + '/refresh_token.txt', 'w') as f:
f.write(refresh_token)
print('\nThe refresh token was stored for you as ' + directory + '/refresh_token.txt\n')
Steps in the "2023" method:
Please note, you must remove statements that print the token from your production code. Those are there just for debugging.
In a Bash terminal on a Windows machine, you can run the program with the parameters you've set.
SASUSER=fill_in_here # SAS user
SASPASS=fill_in_here # SAS user password
CLIENTSECRET=fill_in_here # client secret
# Certificate on a Windows machine and executable is python
python get_token_2023.py https://my_sas_viya_url.sas.com gel_app $CLIENTSECRET $SASUSER $SASPASS 'C:\Users\myuser\Downloads\gelenv_trustedcerts.pem'
A SAS Viya certificate is used here, in the form of a .pem file. The .pem file was copied in the 'C:\Users\...\' folder.
In a Bash terminal on a Linux machine, the above statement would be:
SASUSER=fill_in_here # SAS user
SASPASS=fill_in_here # SAS user password
CLIENTSECRET=fill_in_here # client secret
# Certificate on a Linux machine and executable is python3
python3 get_token_2023.py https://my_sas_viya_url.sas.com gel_app $CLIENTSECRET $SASUSER $SASPASS /home/my_user/.certs/gelenv_trustedcerts.pem
A SAS Viya certificate is used here, in the form of a .pem file. The .pem file is assumed to be present in the '/home/myuser/' folder.
Access tokens have a 1-hour time-to-live (ttl) by default, so it's common to use a refresh token to generate a new access token. The refresh token itself has a 90-day ttl, while the authorization code is good for 30 minutes and single use. The access token generated can be transferred to other notebooks, programs and used for external API calls.
You can use a refresh token to get an access token when the latter expires.
# 1 Packages
import requests, json, os, base64, sys
# 2. Arguments
print ("Number of arguments:", len(sys.argv), "arguments")
#print ("Argument List:", str(sys.argv))
baseURL=str(sys.argv[1])
client_id=str(sys.argv[2])
client_secret=str(sys.argv[3])
pem_path=str(sys.argv[4])
print ("\nWe are going to use a certificate: ", pem_path)
# encode client string
client_string = client_id + ":" + client_secret
message_bytes = client_string.encode('ascii')
base64_bytes = base64.b64encode(message_bytes)
base64_message = base64_bytes.decode('ascii')
# 3. Construct Variables
authUri="/SASLogon/oauth/token#refresh_token"
print('Your SAS VIYA host is ', baseURL, '\n')
print ('\nRefresh the access token by using the refresh token\n')
url = baseURL + authUri
# read the refresh token
directory = 'api'
print('\nRetrieving the saved refresh token\n')
with open("api/refresh_token.txt", "r", encoding="UTF-8") as f:
refresh_token = f.read()
#print(refresh_token)
payload = "grant_type=refresh_token&refresh_token=" + refresh_token
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
'Authorization': "Basic " + base64_message
}
response = requests.request("POST", url, headers=headers, data=payload, verify=pem_path)
#print(response.text)
# process the results
response = requests.request("POST", url, headers=headers, data=payload, verify=pem_path)
access_token = json.loads(response.text)['access_token']
print(json.dumps(response.json(), indent=4, sort_keys=True))
# Create access_token.txt file
with open(directory + '/access_token.txt', 'w') as f:
f.write(access_token)
print('\nThe access token was stored for you as ' + directory + '/access_token.txt\n')
Please note, you must remove statements that print the token. Those are there just for debugging.
In a Bash terminal on a Windows machine, you can run the program with the parameters you've set.
Note that you no longer need the user and the password with the refresh token method. The client, the secret and the refresh token itself are enough to get you an access token. In all the subsequent posts, we will use the refresh token to get a new access token.
CLIENTSECRET=fill_in_here # client secret
# Certificate on a Windows machine and executable is python
python refresh_token_2023.py https://my_sas_viya_url.sas.com gel_app $CLIENTSECRET 'C:\Users\myuser\Downloads\gelenv_trustedcerts.pem'
In a Bash terminal on a Linux machine, you can run the program with the parameters you've set.
CLIENTSECRET=fill_in_here # client secret
# Certificate on a Linux machine and executable is python3
python get_token_2023.py https://my_sas_viya_url.sas.com gel_app $CLIENTSECRET $SASUSER $SASPASS /home/my_user/.certs/gelenv_trustedcerts.pem
Learning how to harness the power of the SAS Information Catalog APIs can unlock a new level of efficiency and customization in managing your SAS Viya assets. By calling them from Python you can open the door to new integrations. This tutorial on acquiring an access token is the first step in that journey. Stay tuned for more in-depth discussions and tutorials in this series.
Read the following post in the series: Download Metadata and Metrics with SAS Information Catalog APIs from Python.
Thank you for your time reading this post. If you liked the post, give it a thumbs up! Please comment and tell us what you think about having conversations with your data. If you wish to get more information, please write me an email.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning and boost your career prospects.