1月 252019
 

Need to authenticate on REST API calls

In my blog series regarding SAS REST APIs (you can read all of my posts on this topic here) I outlined how to integrate SAS analytical capabilities into applications. I detailed how to construct REST calls, build body parameters and interpret the responses. I've not yet covered authentication for the operations, purposefully putting the cart before the horse. If you're not authenticated, you can't do much, so this post will help to get the horse and cart in the right order.

While researching authentication I ran into a couple of resources on SAS and OAuth. First, what I consider the gold standard in Mike Roda’s SAS Global Forum paper OpenID Connect Opens the Door to SAS Viya APIs. We have also re-written the SAS Viya REST API ‘Getting Started’ documentation on developer.sas.com, which covers details on application registration and access token generation. The rewrite includes sample code for both curl and Python.

Consider this post a quick guide to summarize these resources and shed light on authenticating via authorization code and passwords.

What OAuth grant type should I use?

Choosing the grant method to get an access token with OAuth depends entirely on your application. You can start with this guide Which OAuth 2.0 grant should I implement? to understand the basics of OAuth grant type options. For a SAS perspective, refer to Tara St. Clair’s article Building custom apps on top of SAS Viya, Part Three: Choosing an OAuth flow.

This post covers three grant methods: authorization code, client credentials, and password. Authorization code grants are generally used with web applications and considered the safest choice. The client credentials grant is not associated with any user and is scoped according to the authorities registered to the client. Password grants are most often used by mobile apps and applied in trusted environments. The password grant type is not considered secure and should not be used in production environments.

The process, briefly

Getting an external application connected to the SAS Viya platform requires a series of steps. The process below pertain to the authorization code grant type; however, the steps are similar for all grant types.

  1. Use the SAS Viya configuration server's Consul token to obtain an Access Token to register a new Client ID
  2. Use the Access Token to register the new client ID and secret
  3. Obtain the authorization code
  4. Acquire the OAuth access token of the Client ID using the authorization code
  5. Call the SAS Viya API using the access token for the authentication.

The process requires multiple roles. A SAS administrator performs steps 1 and 2. A script or app provides the URL to an end user for step 3. This produces an authorization code and the user plugs it back into the script or application, so it can continue.

Registering the client and getting the authorization code (steps 1,2, and 3) are one-time processes. The access and refresh tokens (step 4) are created once and only need to be refreshed if/when the token expires. Once you have the access token, you can call any API (step 5) if your access token is valid.

The process, in detail

Let's look at each grant type in more detail.

Get an access token using an authorization code

For all three grant types covered, you must register the client. The process explained here is in the context of the the authorization code grant type. The client registration process is the same across all grant types, except for the authorization_code parameter. It must match the grant type procedure followed by the user later on.

Step 1: Get the SAS Viya Consul token to register a new client

The first step to register the client is to get the consul token from the SAS server. As a SAS administrator (sudo user), access the consul token using the following commands:

For SAS Viya 3.5 and before

On the SAS Viya server, run the following command to get the Consul token and add it to the CONSUL_TOKEN environment variable:

$ export CONSUL_TOKEN=`cat /opt/sas/viya/config/etc/SASSecurityCertificateFramework/tokens/consul/default/client.token`

And the response: 64e01b03-7dab-41be-a104-2231f99d7dd8 (when not stored in a variable).

For SAS Viya 2020.1 and later

On the SAS Viya cluster, run the following command to get the Consul token (replace value to fit your environment):

kubectl -n <namespace> get secret sas-consul-client -o jsonpath="{.data.CONSUL_TOKEN}" | echo "$(base64 -d)"

And the response: 64e01b03-7dab-41be-a104-2231f99d7dd8

The Consul token returns and is used to obtain an access token used to register the new application. Use the following cURL command to get the token:

$ curl -k -X POST "https://sasserver.demo.sas.com/SASLogon/oauth/clients/consul?callback=false&serviceId=myclientid" \
     -H "X-Consul-Token: $CONSUL_TOKEN"

And the response:

 {
   "access_token":"eyJhbGciOiJSUzI1NiIsIm...",
   "token_type":"bearer",
   "expires_in":35999,
   "scope":"uaa.admin",
   "jti":"de81c7f3cca645ac807f18dc0d186331"
}

Where serviceid in the URL represents the name of the client to register ('myclientid' in this case). The returned token can be lengthy. To assist in later use, create an environment variable from the returned token:

$ export IDTOKEN="eyJhbGciOiJSUzI1NiIsIm..."

Step 2: Register the new client

Change the client_id, client_secret, and scopes in the code below. For detailed guidance on creating and managing Client IDs and Secrets, refer to this page. Scopes should always include "openid" along with any other groups this client needs to get in the access tokens. You can specify "*" but then the user gets prompted for all available groups. The example below just uses one additional group named "group1". Check with your SAS administrator for which scopes to include. You can find more information on scopes and authorities (related parameter for client credentials grant) in this SAS Communities thread.

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

And the response:

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

Step 3: Approve access to get authentication code

Place the following URL in a browser. Change the hostname and myclientid in the URL as needed.

https://sasserver.demo.sas.com/SASLogon/oauth/authorize?client_id=myclientid&response_type=code

The browser redirects to the SAS login screen. Log in with your SAS user credentials.

SAS Login Screen

On the Authorize Access screen, select the openid checkbox (and any other required groups) and click the Authorize Access button.

Authorize Access form

After submitting the form, you'll see an authorization code. For example, "lB1sxkaCfg". You will use this code in the next step.

Authorization Code displays

Step 4: Get an access token using the authorization code

Now we have the authorization code and we'll use it in the following cURL command to get the access token to SAS.

$ curl -k https://sasserver.demo.sas.com/SASLogon/oauth/token \
     -H "Accept: application/json" -H "Content-Type: application/x-www-form-urlencoded" \
     -u "myclientid:myclientsecret" -d "grant_type=authorization_code&code=YZuKQUg10Z"

And the response:

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

We use the returned token to authenticate and authorize the calls made between the client and SAS. We also get a refresh token we use to issue a new token when the current one expires. This way we can avoid repeating all the previous steps. I explain the refresh process further down.

We will again create environment variables for the tokens.

$ export ACCESS_TOKEN="eyJhbGciOiJSUzI1NiIsImtpZCI6ImxlZ..."
$ export REFRESH_TOKEN="eyJhbGciOiJSUzI1NiIsImtpZC..."

Step 5: Use the access token to call SAS Viya APIs

The prep work is complete. We can now send requests to SAS Viya and get some work done. Below is an example REST call that returns the top level folders.

$ curl -k https://sasserver.demo.sas.com/folders/folders?filter=isNull(parent) \
-H "Authorization: Bearer $ACCESS_TOKEN"

And the (partial) response:

{
    "links": [
        {
            "method": "GET",
            "rel": "collection",
            "href": "/folders/folders",
            "uri": "/folders/folders",
            "type": "application/vnd.sas.collection"
        },
        {
            "method": "GET",
            "rel": "self",
            "href": "/folders/folders?start=0&limit=20",
            "uri": "/folders/folders?start=0&limit=20",
            "type": "application/vnd.sas.collection"
        },
        {
            "method": "POST",
            "rel": "createFolder",
            "href": "/folders/folders",
...

Use the refresh token to get a new access token

To use the refresh token to get a new access token, simply send a cURL command like the following:

$ curl -k https://sasserver.demo.sas.com/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=$REFRESH_TOKEN"

And the response:

{
   "access_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImxlZ...",
   "token_type":"bearer",
   "refresh_token":"eyJhbGciOiJSUzI1NiIsImtpZCSjYxrrNRCF7h0oLhd0Y",
   "expires_in":35999,
   "scope":"openid",
   "jti":"a5c4456b5beb4493918c389cd5186f02"
}

Note the access token is new, and the refresh token remains static. Use the new refresh token for future REST calls. Make sure to replace the ACCESS_TOKEN variable with the new token. Also, the access token has a default life of ten hours before it expires. Most applications deal with expiring and refreshing tokens programmatically. If you wish to change the default expiry of an access token in SAS, make a configuration change in the JWT properties in SAS.

Get an access token using the client credentials grant

The steps to obtain an access token using the client credentials grant are similar to the authorization code. I highlight the differences below, without repeating all the steps. The process for registering the client is the same as described earlier, except for the grant type parameter where you will now use "authorized_grant_types": ["client_credentials"]. With client credentials, there is no concept of a refresh token, so it's been removed from the parameter.

Now that the client is registered, the only thing left is to get the access token. Use the code below to get the token:

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"

That's it. You can now use the access token retuned in the preceeding call to make REST API calls.

Get an access token using the password grant

The steps to obtain an access token using the password grant are again similar to those describe earlier. When registering the client, use the password grant "authorized_grant_types": ["password","refresh_token"].

The client is now registered on the SAS Viya server. To get the access token, we send a command like we did when using the authorization code and client credentials, just using the username and password.

curl -k https://sasserver.demo.sas.com/SASLogon/oauth/token \
     -H "Content-Type: application/x-www-form-urlencoded" 
     -u "myclientid:myclientsecret" 
     -d "grant_type=password&username=sasdemo&password=mypassword"

And the response:

{
   "access_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6Imx...",
   "token_type":"bearer",
   "refresh_token":"eyJhbGciOiJSUzI1NiIsImtpZ...",
   "expires_in":43199,
   "scope":"DataBuilders ApplicationAdministrators SASScoreUsers clients.read clients.secret uaa.resource openid PlanningAdministrators uaa.admin clients.admin EsriUsers scim.read SASAdministrators PlanningUsers clients.write scim.write",
   "jti":"073bdcbc6dc94384bcf9b47dc8b7e479"
}

From here, sending requests and refreshing the token steps are identical to the method explained in the other code examples.

Final thoughts

At first, OAuth seems a little intimidating; however, after registering the client and creating the access and refresh tokens, the application will handle all authentication components . This process runs smoothly if you plan and make decisions up front. I hope this guide clears up any question you may have on securing your application with SAS. Please leave questions or comments below.

Authentication to SAS Viya: a couple of approaches was published on SAS Users.

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)