Building custom apps on top of SAS Viya, Part Three: Choosing an OAuth flow

5

This is the third installment of a series focused on discussing the secure integration of custom applications into your SAS Viya platform. I began the series with an example of how a recent customer achieved value-add on top of their existing investments by building a custom app for their employees and embedding repeatable analytics from SAS Viya into it. Then in the second part, I outlined the security frameworks and main integration points used to accomplish that.

Key takeaways from the previous post

As a quick recap, in the last post I covered how to integrate custom-written applications with the SAS Viya platform using scoped access tokens from SAS Logon Manager. I outlined the returned access tokens need to be included with the REST calls those custom apps make to SAS Viya endpoints and resources. The access tokens contain the necessary information SAS Viya will use to make authorization decisions for every call your app makes. Administrators of your SAS Viya environment have complete control over the rules that determine the outcome of those decisions. I also introduced the primary decision you need to make before you begin integrating your custom app into your SAS Viya environment: whether those access tokens will be scoped in the context of your application (general-scoped) or in the context of each logged-in user of your application (user-scoped).

Now let's go a bit deeper into the authorization flows for both scenarios. TL;DR at the bottom.

Quick disclaimer: The rest of this post assumes you are familiar with the SAS Administration concepts of Custom Groups, granting access to SAS Content, and creating authorization rules. If those topics are unfamiliar to you and you will be implementing this custom application registration, please take a look at the resources linked inline.

General-scoped access tokens

First, when I say "general-scoped access" here, I mean cases where you don't want end users to have to log in (directly to SAS Viya, at least). You don't want the tokens returned by SAS Logon to your custom applications generating authorization decisions based on the individual using your application. In these cases, however, you do still want control over the endpoints/resources your app calls and which CRUD operations it performs on them. Any situation where you'd like to expose some content you've created in SAS Viya to a large scale of users, particularly those that wouldn't have valid login credentials to your SAS Viya environment, fall in this category. There are two main “flows” available to make this happen. Here, “flow” is a term used to describe the process for accessing a protected resource within the OAuth framework.

Password flow

I'll won't go into much detail on this one because the folks behind OAuth 2.0 are suggesting the phase-out of the use of this flow (source one) (source two). Though it technically works for this use case, it does so by essentially using a "service account" so all REST calls your application makes are within the scope of a single UID. You could create specific authorization grants for that user (or a group it's a member of) to make this functional, but it requires that you include the username and password as clear text URL parameters when you request your token. It's just not a great idea and not secure to send this over the wire even if you are using HTTPS. It also creates another sensitive environment variable to manage and, worse, I have even seen this hard coded it into custom application logic.

Client Credentials flow

Interestingly enough, the combination of the security concerns with the Password flow, while still needing to provide specific access levels for a custom application our team was building, is how I found myself wanting to write this series. If you're reading this, you've likely checked out the page on how to register clients to SAS Logon Manger on developer.sas.com. These instructions do not cover the Client Credintials flow though Mike Roda's SAS Global Forum paper, OpenID Connect Opens the Door to SAS Viya APIs, does provide guidance on the client credentials grant type. Remember, these types of scenarios don't warrant concern for which individual users are making the calls into SAS Viya; however, you still will want to restrict which calls your app makes, so follow least-privilege access best practices.

The secret sauce to making this work is registering your application to SAS Logon Manager using a specific, optional key called authorities and setting its value to be a list of custom group(s) giving your application the access to the proper resources and endpoints. Here's where some prior knowledge of creating authorization rules for specific URIs using endpoint patterns and specific principals comes in handy. Check out the documentation linked above if those are unfamiliar terms. We'll see examples of how to implement this flow in the next post in this series.

The diagram below illustrates this flow. Viewing hint: click on the photo to focus on it, and click on the full-screen button to enlarge it.

Figure 1: Visual representation of the Client Credentials OAuth flow

User-scoped access tokens

As a quick recap, here I'm talking about the cases where it does make sense for your application's end users to log in to SAS. All subsequent API calls into SAS Viya resources your application makes should be within the context of what they as an individual user is allowed to do/see/access in SAS Viya. For example, if a user is not in the SAS Administrator's group, then you'll want to ensure any REST calls your custom app makes for that user that would require him to be in the SAS Administrator's group will indeed fail.

Admittedly, this takes more work on the application development side to implement; however, as far as creating and registering the client for your application, this isn't any more complicated than what I've already outlined in this post. By the nature of the flow I'll outline in a minute, the application developer is going to need to add additional logic to handle sessions and/or cookies to obtain, store, check, update, and eventually revoke individual user's authorization codes. When using SAS Viya applications this all occurs behind the scenes. For example, when you first navigate to SAS Visual Analytics (VA) you are re-directed to SAS Logon Manager to log in and get your user-scoped access token. Then you are redirected back to VA with your token. In turn, VA and the supporting services use this token for any subsequent REST calls to other SAS Viya endpoints and resources. When creating custom-developed apps you integrate with SAS Viya for user-scoped access, we need to recreate that baked-in behavior. This is the process I outline below.

Authorization Code flow

A shortened-for-readability version of how this works is:

    1. The user navigates to your application. If they don't already have a valid session with SAS Logon Manager redirection sends them to the same screen they would see when accessing native SAS Viya applications.
      _
    2.  They enter credentials and log in. Then depending on how the client was registered, either:
      • the user manually approves their group memberships which SAS Logon Manager presents to them (thus all the authorization grants for those group(s)). An example of this is seen when logging into SAS Viya and being presented with the option to accept or deny your SAS Administrators group privileges, or
      • their group memberships will be automatically approved for them. This option is more SAS Viya-esque in that, when you log in as a regular user you're not asked to accept your role in any Custom Groups. It is implicitly allowed behind the scenes, so you needn't know what each Custom Group allows. Rather, it is assumed that a SAS Administrator has provided you the right memberships.
      • Note that we will see an example of how to toggle these two options in the next post in this series._
    3. If the user credentials are valid, SAS Logon Manager responds with a user-scoped authorization code. We'll see how to use redirects to get it back to your application in the next part of this series. Your application needs to retrieve and temporarily store the authorization code which will be in a URL parameter on the redirect.
      _
    4. Your application will then need to make another request to SAS Logon Manager on behalf of your user, this time trading the code for an OAuth access token. This is where your apps ability to handle sessions and/or cookies, regardless of programming and code language, starts to come in handy.
      _
    5. Finally, when your user interacts with some part of your application that needs to make an API call to a SAS Viya endpoint or resource, your application needs to pass their user-scoped OAuth token in with the request. Remember, it's a good idea to include some logic to check for expired tokens and be able to refresh and revoke them when necessary as well.

Joe Furbee covers the authorization code process in detail in Authentication to SAS Viya: a couple of approaches. The whole point of using this flow in this manner is to ensure that SAS Logon Manager is responsible for handling individual user credentials rather than your application, which by contrast would then require submitting them over the wire. The diagram below represents the flow.

Figure 2: Visual representation of the Authorization Code OAuth flow

Password flow

In fairness, this technically works here as well, but we already know the drill.

_

Summing it all up (or TL;DR)...

My goal between this post (and in part 2) was to introduce the necessary planning steps prior to registering a custom-developed application to SAS Logon Manager, so it can make REST API calls to SAS Viya endpoints and resources. To recap, the steps are:

1.  Decide whether users should have to log into SAS Viya or not.

    • Is your application serving up generic or "public" content that anyone using your app should have the same level of access to? Note that in this case you could still have a layer of custom login logic to restrict user access to your application, but I'm referencing scenarios where it doesn't make sense for users to log into SAS Viya, especially if they aren't in the configured user base with valid credentials. If you find yourself in this scenario, then proceed to Step 2A.
      _
    • Or, do you want any application API calls to SAS Viya to be within the context of what that individual logged-in user should be able to do? Then proceed to Step 2B.

2A.  Consider using the Client Credentials flow. Set up the security principal(s) and authorization rule(s) to give your application the appropriate permissions to the needed resources and then register your client with the relevant settings.

2B.  In this case, you should consider using the Authorization Code flow. Enhance your custom application's ability to request and handle user- and session-specific authorization codes and tokens, substituting them into subsequent API calls when needed, and then register your client with the relevant settings.

_
In either case, I'll cover examples in the next post in this series.

Share

About Author

Tara St. Clair

Principal Technical Architect, Field Innovation R&D

Tara develops SAS environments from architectural design, through deployment and security modelling, and ultimately onto administrating and consulting. These days she enjoys writing custom Python serverless functions to extend the value of SAS, integrating them into the platform, and sharing her findings along the way. When she's not doing any of those things, she's tending to her 50+ houseplants.

5 Comments

  1. Hi Tara,

    Is it possible to publish a python code as a function and publish on SAS Viya then it can be exposed as API
    with an endpoint to be requested by a client application

  2. Hi, I would like to let an external application to run a job using SASJobExecution API. I need a client_credentials flow, but I'm unsure about how to create the client and how to use it.

    Here's the client I created so far:

    {
    "scope": [
    "openid"
    ],
    "client_id": "myclient",
    "client_secret": "secret",
    "resource_ids": [
    "none"
    ],
    "authorized_grant_types": [
    "client_credentials"
    ],
    "redirect_uri": [
    "/"
    ],
    "autoapprove": [
    "true"
    ],
    "authorities": [
    ""
    ],
    "use-sessions": "true"
    }

    I can successfully get a token using myclient, but then when I use it to run a job in https://sasegpviya.enel.com/SASJobExecution/?_program=xxx I get:
    {
    "errorCode": "-320",
    "message":"The SAS program provided for the job completed execution with at least one error.
    Failed to launch process.
    Failed to launch process: host=e... port=... ssl=true
    Server error: status=0x80BFD100 messages=[ERROR: Access denied.
    ]"}

    I guess because no user is actually mapped to myclient? So how can I allow myclient to run the job?

    Moreover, I don't fully understand what these parameters mean: scope, resource_ids, authorities.

    The goal would be that the external application authenticates with client/secret (only), and then it can run a specific job (and only that one!).

    Can you help me to understand what is the correct way to implement that?

    Thank you very much

    • Tara St. Clair

      Hi Edo - I think reading the last post in this series, Part Four: Examples will help you. Your main issue given the client info that you've included in your comment is that you're not tying the client to any authorization rules that will give it access to the Jobs endpoints it needs via the authorities key. If you still have questions after going through that post, please reach out to me via email at tara.stclair@sas.com and I'd be happy to help you.

Leave A Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back to Top