CLI Authentication with Auth0

Yevgeni Krupetsky
Altostra
Published in
4 min readMay 6, 2020

Authentication with an Identity as a Service provider, such as Auth0, is pretty straight forward in a web application, but we also want to provide the same convenient SSO experience for our CLI users.

In this article, we’ll take a look at the traditional way to do authentication in the terminal and how we can improve the experience for our users.

TL;DR

Skip to the Implementation section to see the steps and code samples.

The code in this article was simplified for a better reading experience. We also published an open source library that implements the solution and can save you some work.
The library sources are available at
https://github.com/altostra/altostra-cli-login-auth0 and an NPM package at https://www.npmjs.com/package/@altostra/cli-login-auth0

The traditional solution: using secrets

One way to approach this challenge is to generate a secret for users to store in a file manually (e.g. AWS access keys, GitHub SSH Keys, and NPM Auth Tokens).

There are a few drawbacks to this approach:

  • The secrets don’t rotate — an attacker may use a stolen secret until the user manually revokes it
  • Users must log in and create a secret for each machine they use
  • Users must manually delete the files that hold the secrets or revoke them to log out

Making users manually manage their secrets works, but it is not the best experience for them. If you care to provide your users with a better experience, there is another way.

The better solution

After reading the Auth0 documentation and blog, it is clear how we can obtain an access token for the user from the terminal and still enjoy a web authentication experience with SSO:

  • Start an HTTP server on the localhost address
  • Open a parameterized Auth0 authorization URL in a browser
  • Let the user login the same as they would in a web application
  • Handle a redirect request from Auth0 to the localhost server, obtain the authentication code, and stop the server
  • Call the Auth0 Management API to obtain an access token for the user

Once we obtain the access token, we can store it in a file, accessible only to the user, just as we would store secrets. Later, any of our locally running apps can use this token to authenticate. This process automates the manual work done by the user in the common solution while providing a web login experience with SSO.

The benefits

  • We can enforce expiration on the access token and have the user re-authenticate, thus rotating credentials periodically.
  • The login process is simple and doesn’t take much time.
  • The process of setting up a new machine is quick and simple.
  • We can provide the user with a log-out command that deletes the stored token and revokes it with Auth0.

Implementation

Step 1: Start a local HTTP server

Start an HTTP server on the localhost address with the custom port 4242 that will handle authentication responses from Auth0.

Start an HTTP server

Step 2: Open an Auth0 authentication URL

Using data from an Auth0 account and application, we construct an authentication URL:

https://domain.auth0.com/authorize
?response_type=code
&code_challenge_method=S256
&code_challenge=<code-challenge>
&client_id=<client-id>
&redirect_uri=http://localhost:4242
&scope=<token-scope>
&audience=<token-audience>
&state=<state>

The parameters are:

  • domain.auth0.com is your Auth0 domain, you can find it in the settings page of your Auth0 applications in the Auth0 management console.
  • response_type must be set to code.
  • code_challenge_method should be set to S256. The other possible value is clean, but that would be a bad idea, security-wise.
  • code_challenge must be a string generated for each request, we use it to validate the response.
  • client_id is the Auth0 application Client ID. It's located in the settings of the application in the Auth0 management console.
  • redirect_uri is the URI to which the request with an authorization code should redirect. We must set it to the localhost address with the same port number that we used to start the HTTP server.
  • state is an "opaque" value used as a CSRF-token to prevent CSRF attacks.

The full API documentation is available here.

Step 3: Handle the response

After the user completes the authentication in the browser, which either succeeds or fails, the login page redirects the user to the URL we provide in redirect_uri. The query string of the URL contains either a code value, when successful or an error and error_description values when unsuccessful.

Keep in mind that the response to the redirected request must be an HTML page to inform the user about the authentication process result.

Step 4: Get the access token

Using the code we obtained in step 3, we call the Auth0 authentication API to obtain an access token for our user. We provide the code_verifier and the authentication code values. The request looks like this:

URL     : https://domain.auth0.com/oauth/token
Method : POST
Headers : ContentType: application/x-www-form-urlencoded
Body : grant_type=authorization_code&client_id=<client-id>&code_verifier=<code-verifier>&code=<autnentication-code>&redirect_uri=<uri>
  • domain.auth0.com is your Auth0 domain, you can find it in the settings page of your Auth0 applications in the Auth0 management console.
  • grant_type must be set to authorization_code, indicating that we're also passing the authentication-code parameter.
  • client_id is required and must be the Auth0 application Client ID.
  • code_verifier is required and must be the code_verifier value generated at the beginning of the process.
  • code is required and must be the authentication code we got from the login page redirect.
  • redirect_uri is required and must be the same as the redirect_uri value used in the authorization URL.

The full API documentation is available here.

Next Steps: Use the authentication token

Next, we store the access token in a file accessible only by the user, and then use it to authenticate to our services.

--

--