Protecting Auth0 App Sign-In with SGNL

Introduction

Protected Systems are applications, services, or infrastructure that you want to protect with SGNL. In this guide, we’ll describe how to achieve fine-grained access control at sign-in time with Auth0 and SGNL, enabling the right amount of access to applications and infrastructure configured with Auth0. If you’d like to learn more about whether fine-grained Sign-In Policies with Auth0 and SGNL is right for your enterprise, visit our SGNL for Auth0 Blog.

With this integration, Auth0 need not know about the policies, systems of record, or any of the data in SGNL - it simply needs to pass to SGNL:

  • Who/What is requesting the access (The Principal)
  • (Optional) What is attempting to be accessed (The Asset)
  • (Optional) What operation is being attempted on the asset (The Action)
  • An access token that ensures the Protected System is a legitimate caller into SGNL

Prerequisites

  • An Auth0 Tenant
  • A SGNL Client
  • A SGNL User Account with Admin privileges
  • (Optional) 1 or more policies that you want assigned to the integration

Creating a Protected System in SGNL

  1. Log-In to your SGNL Client with an Admin Account
  2. From the left navigation pane, select Protected Systems and Add, or simply click Add from the SGNL Dashboard
  3. Select ‘Auth0’ from the Identity Providers category in the list of integrations
  4. Give your integration a descriptive display name and description
  5. Specify the Default Policy to be applied to your App
    • Allow: If no policies provide a decision for an access request, SGNL will respond to the access request with an Allow decision
    • Deny: If no policies provide a decision for an access request, SGNL will respond to the access request with a Deny decision
  6. Next, you’ll need to configure which identifier Auth0 is using to describe your user/principal
    • This is likely your Auth0 user’s email address or login name. This should be in the format of the Principal ID of the user that will request access to the Protected System.
    • e.g. If an Auth0 user will be requesting access to this Protected System with the Principal ID as their login name, the principal identifier should be the Auth0 login name.
  7. You’ll also need to define the identifiers for the types of Assets that you are looking to protect
    • This might be app identifiers sourced directly from Auth0, or something more granular within one of your other Systems of Record
  8. Once configured, click Continue to save your configuration and move on to other configuration steps

Configuring Authentication

  1. Authentication ensures that only authorized systems can make requests into SGNL, as well as verifying the identity of an integration in order to effectively evaluate Policies - to access Authentication settings, open your AWS protected system and select the Authentication tab

    SGNL - Authentication

  2. Click Generate Token

  3. Give your token a descriptive name so that you know how it’s being used in the future and click to Generate Token

    SGNL - Generate Token

  4. On the next screen, copy the token - this will be used by Auth0 to make access requests to SGNL using the SGNL Access Service API

    Note: The value of this token is not available again after this screen, so ensure you securely store it for steps later in this guide

    SGNL - Token

Integrating Auth0 with SGNL

The request flow from Auth0 to SGNL is straightforward. When a user authenticates with Auth0, a request is sent from the Auth0 authorization server to the SGNL Access Service API. The policy engine evaluates the applicable authorization policy and returns an allow or deny to the Auth0 custom post-login action. If the response is a deny, the post-login action sets a deny status via the Auth0 PostLoginAPI.

Auth0 Login Flow

  1. An application (e.g. React single page application) makes an authorization request to the Auth0 authorization server.
  2. Once Auth0 performs coarse grained authorization and authentication, it instantiates the Auth0 post-login action and sends an authorization query to the SGNL access service.
  3. (A) If the policy decision is allowed, the SGNL access service sends the allowed response back to the Auth0 post-login action. (B) If the policy decision is denied, the SGNL access service sends the deny response back to the Auth0 post-login action.
  4. (A) If the post-login action receives an allow, then it allows the login flow to continue. The Auth0 authorization server then sends an authorization code back to the application. (B) If the post-login action receives a denial, then the Auth0 authorization server halts the login flow and sends a 302 redirect with an error message and description.
  5. If the application receives an authorization code from the Auth0 server, the application then makes a request to the Auth0 server’s token endpoint to retrieve the access and id tokens for the user.
  6. The Auth0 authorization server returns both the access and id tokens to the application.

The following code snippet is an example implementation of the Auth0 custom action for calling the SGNL access service API. This is the function the Auth0 authorization server calls for every protected API or application request. The request context is passed in the function’s request parameter.

You can download the full Auth0 post-login action Node.js example from the SGNL examples repository.

Code snippet from The Auth0 post login flow

/**
 * Handler that will be called during the execution of a PostLogin flow.
 *
 * @param {Event} event - Details about the user and the context in which they are logging in.
 * @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
 */
exports.onExecutePostLogin = async (event, api) => {
  const axios = require("axios");
  // Create an instance of Axios HTTP client

  const sgnl_api = axios.create({
    baseURL: event.secrets.sgnl_url,
    timeout: 1000,
    headers: { Authorization: event.secrets.Token },
  });

  // Output requested resource to log for debug
  console.log("URI: " + event.request.query.redirect_uri);

  // Call SGNL access service API
  await sgnl_api
    .post(event.secrets.sgnl_url, {
      principal: {
        id: event.user.email,
      },
      queries: [
        {
          assetId: event.request.query.redirect_uri,
          action: event.request.method,
        },
      ],
    })
    .then(function (response) {
      console.log(
        "SGNL policy decision: " + response.data.decisions[0].decision
      );
      // Deny access if SGNL policy results in a deny.
      if (response.data.decisions[0].decision == "Deny") {
        api.access.deny(
          `SGNL Authorization: Access to ${event.client.name} is not allowed.`
        );
      } else {
        // Success
      }
      // uncomment for debug purposes
      // console.log(response);
    })
    .catch(function (error) {
      console.log(error);
    });
};

If the post-login action allows the authorization process to continue, Auth0 continues with the authorization request flow to the sample React application and subsequent request to the OAuth token endpoint (with the authorization code), to retrieve the access and id tokens. Here is a sample response containing the access and id tokens back to the sample React application:

{
  "access_token": "{Access token string.}",
  "id_token": "{ID Token string.}",
  "scope": "openid profile email",
  "expires_in": 86400,
  "token_type": "Bearer"
}

If the post-login action calls the deny method for Auth0’s PostLoginAPI, then the Auth0 authorization server sends a redirect (HTTP 302) to the sample React application callback URL with an error in the query string.

For more details and samples, visit SGNL’s Examples GitHub Repo

Assigning Policies

  1. Once the Auth0 integration is created, you can start assigning versions of Policies - to get started, select Policies from the tabs in your newly created integration

    SGNL - Policies

  2. Select ‘Assign Policies’

  3. Select:

    • The Policies you want to apply to the integration with the check box
    • The version of the Policy you want applied

    SGNL - Select Policies

  4. Click Next once you have the Policies and Versions configured as is appropriate

  5. Select the Enforcement mode for the Policies you chose in the previous step

    • Simulated: Policy Versions that are being simulated will only log their access decision in the SGNL logs and will not impact the access decision that SGNL hands back to an integration. Simulated policies are useful for performing what-if analysis of new policy versions as well as debugging policy changes.

      Note: It’s considered best practice to start with policies in Simulated mode, to verify that policies have been created an applied as expected

    • Enforced: Policy Versions that are being enforced will impact the access decisions that SGNL hands back to an integration. Enforced Policies will determine access for an integration

    SGNL - Set Enforcement

  6. Select your desired Enforcement mode and select Assign

  7. Versions of Policies will now be Assigned to your integration

    SGNL - Policy Assignments