Skip to Content
Technical Articles
Author's profile photo Jascha Kanngiesser

@sap/dwc-cli: Getting Rid of Passcodes Thanks to OAuth Client Support

This blog post is part of a series of blogs I published about @sap/dwc-cli. Find all blog posts related to this topic in my overview blog post here.

The Node.js-based Command-Line Interface (CLI) for SAP Data Warehouse Cloud, @sap/dwc-cli hosted on npmjs.com, allows you to interact with your SAP Data Warehouse Cloud tenant from the terminal or command line. With version 2022.20 of the CLI, you can now use OAuth client authentication instead of passcodes, allowing you to issue multiple commands without the need to re-authenticate for up to 720 hours!

Introduction

With previous versions of @sap/dwc-cli, you had to provide a passcode for every command you executed. This is already cumbersome in a foreground scenario with you sitting in front of your PC and using the CLI manually on the command line. It gets even worse when trying to use the CLI in the background, for example in an automated script or a CI/CD pipeline.

Thanks to the latest developments in the area of @sap/dwc-cli, you can now create an OAuth Client for Interactive Usage and authenticate using the provided Client ID and Client Secret. After you created an OAuth Client for Interactive Usage, you can log in once and run multiple commands without the need to authenticate again for the next 720 hours.

In this blog, I show you how to create an OAuth Client for Interactive Usage and different ways how you can use it to issue commands using the CLI.


Please note: This update includes a few additional essential changes I’d like to highlight here:

  1. Short flags of some options changed from lower case to upper case. Option -s, –space changed to -S, –space (capital -S), option -d, –definitions changed to -D, –definitions (capital –D).
  2. Commands with a hyphen, except for passcode-url, like cache-*, changed to cache *, eg cache-init changed to cache init.

Creating an OAuth Client

Following the official SAP Help page for creating an OAuth Client for Interactive Usage are the steps to take in a non-SAP data center.

Log in to your SAP Data Warehouse Cloud tenant and navigate to the App Integration page. Depending on whether your tenant is running in a Two Tenant Mode or One Tenant Mode setup, you need to take a different navigation route. In a One Tenant Mode system (that is, your SAP Data Warehouse Cloud and SAP Analytics Cloud system share the same URL, which only differs in the path in parts), you can configure a new OAuth Client in your connected SAP Analytics Cloud tenant. From the app switcher select Analytics (1), choose System > Administration (2), then click on App Integration (3), and finally hit Add a New OAuth Client (4).

Picture%201%20-%20Adding%20a%20new%20OAuth%20Client

Picture 1 – Adding a new OAuth Client

In a Two Tenant Mode system (the URL for both services is different), you can stay in the Data Warehouse app and choose System > Administration (2), then click on App Integration (3), and finally hit Add a New OAuth Client (4).

To create a new OAuth Client to use with the CLI, you only need to provide a meaningful name. As a purpose, choose Interactive Usage and hit Add. You can leave the Redirect URI empty. When creating an OAuth Client for Interactive Usage only, you need to log in once with your business user account to retrieve the initial access token and refresh token you hand over to the CLI for executing commands.

Picture%202%20-%20Creating%20a%20new%20OAuth%20Client

Picture 2 – Creating a new OAuth Client

After you created a new OAuth Client, you can see a new entry on the App Integration overview page. You need to remember/copy the Authorization URL and Token URL for later use (1). To copy the Client ID and Client Secret, hit the Edit OAuth Client button (2).

Picture%203%20-%20New%20OAuth%20Client%20on%20App%20Integration%20Overview%20Page

Picture 3 – New OAuth Client on App Integration Overview Page

You can find the Client ID (1) and the Client Secret (2) in the dialog. Hit the Show secret button (2) to reveal the Client Secret.

Picture%204%20-%20OAuth%20Client%20Details

Picture 4 – OAuth Client Details

Using OAuth Clients with @sap/dwc-cli

Now that you have the Authorization URL, Token URL, Client ID, and Client Secret, you can use these information to log in with your business user account using the CLI and then execute as many commands as you like up to 720 hours before you need to log in again and provide a new refresh token. You can provide the secrets in all different ways supported by the CLI, see the README. In addition, you can create a JSON file containing the secrets and pass it to the CLI using the -s, –secrets-file option. In the following section, I will demonstrate how to pass along the secrets using options and using a file.

To get to know the names of the different options for passing the secrets to the CLI, use option -h, –help (more options have been removed to improve readability):

$ dwc login --help
Usage: dwc login [options]

log in to your account using interactive OAuth authentication

Options:
  -c, --client-id <id>           client id for interactive oauth session authentication (optional)
  -C, --client-secret <secret>   client secret for interactive oauth session authentication (optional)
  -A, --authorization-url <url>  authorization url for interactive oauth session authentication (optional)
  -t, --token-url <url>          token url for interactive oauth session authentication (optional)
  -h, --help                     display help for command

Code Sample 1 – Overview of Options for Passing Secrets

Passing Secrets as Options

We can use the options shown above to log in with our business user account for the tenant we created the OAuth Client for. Currently, it is not possible to log in simultaneously with different accounts for the same tenant or multiple tenants.

When running the dwc login command and specifying the options, a browser window opens requiring you to log in with your business account details. After successful login, a success message is shown and you can close the tab or window.

Picture%205%20-%20Log%20In%20Passing%20Secrets%20as%20Options

Picture 5 – Log In Passing Secrets as Options

After you logged in, you can display the locally stored secrets including the access token, refresh token, and expiry time, … using the dwc secrets show command:

$ dwc secrets show
{
  "client_id": "...",
  "client_secret": "...",
  "authorization_url": ".../oauth/authorize",
  "token_url": ".../oauth/token",
  "access_token": "....",
  "refresh_token": "...",
  "expires_in": 3599,
  "token_type": "bearer",
  "id_token": "...",
  "scope": "...",
  "jti": "...",
  "expires_after": ...
}

Code Sample 2 – Displaying Locally Stored Secrets

Now that you are logged in, you can run as many commands as you like without the need to pass along a passcode or any other secrets again for the next 720 hours! Isn’t this great?! 😊 The CLI uses the access token and refresh token it retrieved when running the dwc login command to authenticate any further command. After 720 hours, you have to log out and log in again to refresh the locally stored refresh token before you can execute additional commands.

Passing Secrets via File

To improve security and not reveal any secrets to someone browsing your terminal’s history, you can also put the secrets into a file and point the CLI to the file’s location when logging in or executing another command (to omit the login step, you can retrieve the access token yourself and pass it to the CLI directly to authenticate commands, see next section).

The file must contain either all information needed to retrieve the access token and refresh token like Client ID, Client Secret, Authorization URL, and Token URL, or you can only provide the access and refresh token instead. Whatever values you provide, you have to provide them in the form of a simple JSON file, with the property names being equal to the respective option names with leading being replaced with empty space, being replaced by _, so for example –client-id becomes client_id. You can also run the dwc secrets show command as shown in the above code sample to get an idea about the property names and which properties you can supply.

// my-secrets.json

{
  "client_id": "...",
  "client_secret": "...",
  "authorization_url": ".../oauth/authorize",
  "token_url": ".../oauth/token"
}

Code Sample 3 – Secrets JSON File

Then, run the dwc login command and specify the path to the secrets file to log in:

$ dwc login --secrets-file /path/to/my-secrets.json

Code Sample 4 – Logging In Using Secrets File

To remove any locally stored secrets, you can run the dwc logout command. To verify that the secrets have been removed successfully, you can run the dwc secrets show command and expect it to fail:

$ dwc logout
$ dwc secrets show
No secrets exist
Failed to display locally stored secrets for interactive OAuth authentication

Code Sample 5 – Logging Out

Directly Passing Access Tokens and Refresh Tokens

It might make sense in your scenario to directly pass the access token and refresh token you retrieved in another way than using the dwc login command and pass both tokens to the CLI instead of Client ID, Client Secret, … This way, the CLI uses the passed tokens to authenticate any command. Again, you can pass the tokens as options (use the -h, –help command to get to know the right option names) or use a JSON file as shown before.

$ dwc cache init --host https://... --access-token a%bak... --refresh-token ce$z2....

Code Sample 6 – Passing Access Token and Refresh Token as Options

Retrieving Access and Refresh Tokens Manually

If you are using the CLI in an automated setup, for example, a script or a CI/CD pipeline, you may want to retrieve the access token and refresh token manually, and provide the tokens together with the information about the Authorization URL, Token URL, Client ID, and Client Secret in a file to the CLI. This way, you don’t need to log in first before executing commands, and you can update the refresh token shortly before it expires after 720 hours.

There are at least two different ways how to retrieve the tokens manually. Either you can use the dwc login command and then run dwc secrets show to display the tokens, or you can follow the login steps manually and use an HTTP client tool of your choice, for example, Postman or curl, to retrieve the tokens. Above you have already read about how to work with the two commands dwc login and dwc secrets show. In this section, I will show you how to follow the login steps manually and retrieve the tokens using Postman and curl.

First, you need to retrieve the temporary code which you later use to retrieve the actual tokens. To retrieve the code, you use the Authorization URL you retrieved from the App Integration page in your tenant. You construct the target URL following this syntax:

<authorization URL>?response_type=code&client_id=<client ID>

https://myhost.com/oauth/authorize??response_type=code&client_id=myclientid

Code Sample 7 – URL to Retrieve Temporary Code

Make sure to URI encode the Client ID. Open this URL in your browser. If not logged in already, you are forwarded to your IdP’s login page.

Picture%20X%20-%20Login%20Page

Picture 6 – Login Page

After you logged in, you are forwarded to the Redirect URI you entered when creating the OAuth Client, or localhost:8080/?code=<code> if you did not enter any explicit Redirect URI. In any way, the temporary code is added as a query parameter to the URL.

Picture 7 – Temporary Code as Query Parameter

Second, you need to send a POST request to the Token URL including the temporary code, Client ID, and Client Secret. The response contains the tokens, besides other things.

Picture%208%20-%20Basic%20Auth%20with%20Client%20ID%20and%20Client%20Secret

Picture 8 – Basic Auth with Client ID and Client Secret

Picture%209%20-%20Custom%20Header%20x-sap-sac-custom-auth

Picture 9 – Custom Header x-sap-sac-custom-auth

Picture%2010%20-%20Temporary%20Code%20in%20Request%20Body

Picture 10 – Temporary Code in Request Body

When the response returns with status 200 OK, you can find the tokens in the response body.

Picture%2011%20-%20Tokens%20in%20Response%20Body

Picture 11 – Tokens in Response Body

Alternatively, you can use curl. To base64-encode the Client ID and Client Secret, you can, for example, use an online encoder (ideally you do this offline though, to ensure no secret information is shared with anyone).

$ curl -X POST <token URL> \
-H "Authorization: Basic <Base64 encoded <client ID>:<client Secret>>" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "x-sap-sac-custom-auth: true" \
-d "response_type=token&grant_type=authorization_code&code=<code>"

Code Sample 8 – Use curl to Retrieve Tokens

You can paste the tokens into a JSON file and pass it to the CLI using the -s, –secrets-file option or pass the tokens directly to the CLI, for example as options as seen in Code Sample 6 above.

Conclusion

I’d be happy to hear your thoughts, ideas, and comments on this tool and what you think would be a nice-to-have enhancement to the CLI, making your life and work with SAP Data Warehouse Cloud easier. Let me know in the comments!

Further Reading

Command-Line Interface for SAP Data Warehouse Cloud on npmjs.com

Command-Line Interface for SAP Data Warehouse Cloud on SAP Help

Assigned Tags

      4 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Jens Rottmann-Matthes
      Jens Rottmann-Matthes

      Hi Jascha,

      thank you for the update! I really use the cli a lot and it makes my daily work a lot easier. I will try the OAuth possibility as soon as I find time and then update my scripts based on the cli accordingly.

      Best wishes,

      Jens

      Author's profile photo Xavier Polo
      Xavier Polo

      Great!

      looking forward to having a moment to try it out!

      Author's profile photo Roland Kramer
      Roland Kramer

      Hello Jascha Kanngiesser

      Thanks for the nice Introduction of the new Functionality.
      I have added your Information to my Blog - proper SAC Connection

      Best Regards Roland

      Author's profile photo Malte Haring
      Malte Haring

      Hi Jascha Kanngiesser

      thanks for explaining this update. The new login works fine if I do it from the command line. However, when I use it As a Node.js module dependency as described here, it fails to initialize the cache:

       

      Do you have any idea why this fails? Is it something I am doing wrong?

      Best Regards,

      Malte