close icon
Security

Continuous Session Protection Now Available for Enterprise Customers

Continuous Session Protection empowers customers to meet a wide range of session and refresh token security needs, including custom lifetimes and revocation capabilities. Let’s dive deeper into how these features can enhance your security strategy.

October 03, 2024

As part of our commitment to making the internet more secure, we are thrilled to announce the General Availability of Continuous Session Protection, a suite of features available in Actions that further enhance our Session Management capabilities for greater security beyond login.

To support our continued expansion of Auth0's extensibility capabilities, Continuous Session Protection gives developers even greater control over monitoring user sessions and the ability to build custom logic within Actions to revoke sessions or deny user access based on factors like organization policies, suspicious activity, and security risk assessments.

This new suite of features empowers developers to use Action Extensibility Points to:

  • Access User Session Attributes: Gain detailed insights into user session attributes, such as IP addresses, session creation time, device information, and more.
  • Access Refresh Token Attributes: Retrieve critical details about refresh tokens, including their creation and expiration times, as well as associated device information and session IDs.
  • Set Custom Expiry and Idle Timeouts: Define custom expiry and idle timeout values for both sessions and refresh tokens, tailored to specific organizational or connection needs.
  • Revoke Sessions and Refresh Tokens: For enhanced security, implement custom logic or risk-based assessments to revoke sessions and refresh tokens.

These capabilities are designed to give developers greater flexibility to address a variety of use cases related to session and refresh tokens. This helps ensure identity management processes are both secure and adaptable to diverse customer needs.

Here are some of the most common use cases addressed:

  • Set Custom Timeouts: Set custom session and refresh token timeouts based on organizational or connection-specific policies. This ensures that sessions adhere to the security requirements of different user groups and organizations.
  • Enhanced Security Checks: Implement additional security measures during session renewals or refresh token exchanges, such as checking device, IP, or other session attributes, to enhance protection against unauthorized access.
  • Revoke suspicious sessions and prevent session hijacking: Use custom logic to revoke or deny user access dynamically based on factors such as suspicious activity, organizational policies, or security risk assessments.
  • Improve user profile insights and personalization: Use session and refresh token information to enrich user profile data, improving user tracking and the ability to deliver user insights and personalization.

These features act as building blocks that can be combined to fulfill numerous use cases, offering developers a foundation for creating more customized and secure authentication workflows. As we continue to enhance our platform, we will be adding more "building blocks" to make these capabilities even more powerful and flexible, further empowering developers to meet evolving security and business needs.

Increasing Security Options by Revoking Sessions During Authentication

In some scenarios, developers may need to revoke a user’s session entirely during the authentication flow. While Auth0 already allows you to deny authentication using api.access.deny(), there are cases where you want to go further and ensure that any existing session is also revoked. This helps maintain a higher level of security by forcing the user to re-authenticate with their credentials, ensuring the session cannot be hijacked or misused.

For example, if you detect suspicious behavior during authentication—such as an unauthorized attempt to access restricted areas—you can revoke the session entirely using api.session.revoke(). This ensures the session is terminated immediately, and the user must provide their credentials again in order to re-establish a secure session.

The difference between api.access.deny() and api.session.revoke() is important:

  • api.access.deny(): Denies access to a specific transaction but keeps the session active, allowing users to access other applications without re-authentication.
  • api.session.revoke(): Fully terminates the session, requiring the user to re-enter credentials before continuing.

By using these features, you can increase the flexibility and security of your authentication pipeline, ensuring that your sessions remain protected from unauthorized access or suspicious behavior.

Use Case: Securing Access for BizSuite0’s Customers

In this use case, we consider BizSuite0, a SaaS company that offers both B2B enterprise solutions and B2C tools for individual professionals such as accountants. BizSuite0’s solutions include payroll, HR, sales systems, and tools tailored specifically for accountants who can use the platform as individuals.

Now, we will explore the journey of BizSuite0 using Auth0 and Continuous Session Protection. BizSuite0’s requirements differ slightly between B2B and B2C use cases. While in B2B use cases they apply a set of standard configurations, they also offer tailored security requirements based on customer requests. In the B2C accountant app, the requirements are different, as we will see below.

For B2C use cases, BizSuite0 decided to enforce an absolute timeout of 24 hours and an idle session timeout of 1 hour for all customers. This balances user convenience and security.

Travel0: A B2B Enterprise Customer

Travel0 is an enterprise customer of BizSuite0. For this example, we will consider three main user groups within Travel0: Sales users, HR users, and an ex-employee. Travel0 requested the following specific security requirements:

  • R1 - Access Control: All Travel0 employees have access to the payroll system, while the HR team has access to both HR and the payroll system.
  • R2 - Session Management: Travel0 mandates a maximum idle timeout of 10 minutes and an absolute expiration of 30 minutes for any sessions.
  • R3 - Employee Offboarding: Former Travel0 employees can still access the payroll system for up to 1 month if they link their personal account before leaving.
  • R4 - Security Measures: To prevent session hijacking or unauthorized access, Travel0 requires that sessions must remain tied to the same device and network throughout their duration. If any changes are detected in the user's IP address, ASN (Autonomous System Number), or browser/device (user agent), the session should be immediately revoked.

BizSuite0 Tools for Accountants (B2C)

For BizSuite0’s B2C offerings, specifically the accountant app, the security requirements are tailored to individual users, ensuring convenience while maintaining security due to the sensitive nature of financial data.

BizSuite0 has established the following security requirements for their accountant tool:

  • Longer Absolute Timeout (24 hours): Since accountants are expected to work throughout the day, an absolute session timeout of 24 hours is set to avoid unnecessary disruptions.
  • Shorter Idle Timeout (15 minutes): Given the sensitivity of the data, a shorter idle timeout is enforced. If an accountant is inactive for 15 minutes, their session expires to prevent unauthorized access.

Additionally, BizSuite0 has implemented the following measures to enhance session security for accountants:

  • Risk-Based Session Timeout: If an accountant authenticates using weaker first factors (e.g., username/password without MFA), the session's absolute and idle timeouts are reduced. For example, a 12-hour absolute timeout and a 10-minute idle timeout are enforced when MFA isn’t used, promoting stronger authentication methods.
  • Geolocation-Based Session Revocation: If an accountant logs in from a high-risk location flagged by Auth0's risk assessments (e.g., an unfamiliar or untrusted IP address), their session can be automatically revoked to prevent potential security breaches.

Auth0 Tenant Configurations

First, we will configure some tenant-level features in Auth0 to meet BizSuite0's requirements, covering both the B2C and B2B use cases mentioned above.

Applications Setup

BizSuite0 currently manages three applications:

  • HR: Available for enterprise customers configured as Business Users in the application configuration
  • Payroll: Available for enterprise customers configured as Business Users in the application configuration
  • Accounts0: Available for both enterprise and individual (B2C) customers.

Applications Setup

Applications Setup

Applications Setup

Applications Setup

Since Accounts0 has specific timeout configurations, we will use application metadata to configure its session timeouts. For consistency and simplicity in the Actions code, we will use standard metadata names for both application and organization configurations, ensuring the values are always in milliseconds.

  • absolute_lifetime: Defines the absolute session expiration time. For example, 24 hours in milliseconds = 86400000.
  • idle_lifetime: Defines the idle timeout. For example, 15 minutes in milliseconds = 900000.

Applications Setup

Enterprise Users and Organization-Level Configuration

For enterprise customers, BizSuite0 utilizes Auth0’s Organizations feature. Organizations allow BizSuite0 to manage their customers, such as Travel0.

alt_text

As part of the Travel0 configuration, we can assign Organization-level metadata (idle_lifetime and absolute_lifetime). These metadata values define specific expiration and idle timeout settings for the organization that override the default tenant configuration.

Configuration

Implementing Custom Session Timeouts Using Actions

To apply custom session timeouts, we will create an Action that uses the new event.api.setExpiresAt() and api.session.setIdleExpiresAt() functions. These functions allow us to configure custom session expiration times and idle timeouts based on the metadata values.

Example Users

For this example, we will configure timeouts for four users:

  1. John Doe — An ex-Travel0 employee who has already linked his personal Gmail account with his Travel0 account.
  2. Hazel Nutt — A Travel0 HR employee.
  3. Ann Chovey — A Travel0 Sales employee.
  4. John McClane — An independent accountant using the Accounts0 application.

Writing Custom Actions

Now, it’s time to leverage the full potential of Auth0’s extensibility points! We will write a few Actions to demonstrate how to apply custom session management logic, including organization and application-specific configurations, role-based session timeouts, and risk-based logic.

We will split the logic for handling authentication and session management into three distinct actions, executed in the following order:

  1. Check User Access: The first step is to verify if the user has the appropriate access to the application or resource they are trying to access. For this example, we will assume that all users have access to the Accounts0 app.
  2. Risk Analysis: Next, we will evaluate whether there are any risks associated with this authentication attempt. The risk analysis will differ between B2C (individual) and B2B (enterprise) users. We will include logic to check the user's context and apply appropriate security measures, such as geolocation-based session revocation for high-risk situations.
  3. Timeout Configuration: Finally, if the user passes the access and risk checks, we will configure the session's absolute and idle timeouts using the new Auth0 extensibility functions (setExpiresAt() and setIdleExpiresAt()). These custom timeouts will be based on organization-level or application-level metadata and user roles.

Action 1: Check User Access

In this action, we verify whether a user has access to the application they are attempting to access. Based on the result, we either deny access to the application or fully revoke the session. Since BizSuite0 has both enterprise (organization-based) and non-enterprise (non-organization) users, this action will:

  1. Check if the user is part of an organization. If not, we skip any further checks.
  2. Verify if the user is an ex-employee and apply the correct logic based on their status.
  3. Check if the user has access to the HR application based on their role.
  4. Handle SSO and first-time login scenarios appropriately.
    /**
     * 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 isPartOfOrg = event.organization; // Flag to check if the user is part of an organization

      // If the user is not part of an organization, no further checks are needed.
      if (!isPartOfOrg) {
        return;
      }

      const clientName = event.client?.name;
      const { app_metadata: appMetadata, roles = [] } = event.user || {};

      // Check if the user is an ex-employee based on departureDate in app_metadata
      if (appMetadata?.departureDate) {
        const departureDate = new Date(appMetadata.departureDate);
        const daysSinceDeparture = calculateDaysDifference(departureDate, new Date());

        if (daysSinceDeparture > 30) {
          api.session.revoke("You no longer have access to this account.");
          return;
        }
      }

      // Check if the user is an HR employee and accessing the HR app
      const isHREmployee = roles.includes("hr");

      if (!isHREmployee && clientName === "HR") {
        // If the user is not an HR employee, deny access to the HR app
        if (event.session?.clients?.length) {
          api.access.deny("You don't have access to the HR application.");
        } else {
          api.session.revoke("You don't have access to the HR application.");
        }
        return;
      }

      // No restrictions for Accounts0 app
    };

    /**
     * Helper function to calculate the difference in days between two dates.
     * 
     * @param {Date} date1 - The earlier date.
     * @param {Date} date2 - The later date (e.g., current date).
     * @returns {number} The number of days between date1 and date2.
     */
    function calculateDaysDifference(date1, date2) {
      const timeDifference = date2.getTime() - date1.getTime();
      return timeDifference / (1000 * 3600 * 24); // Convert milliseconds to days
    }

In this action, we are doing the following checks:

  1. Organization Check: The action starts by checking if the user is part of an organization using event.organization. If the user is not part of an organization, no further checks are needed, and the code exits early.
  2. Ex-Employee Check: If the user is part of an organization, we check whether they are an ex-employee by inspecting their departureDate in app_metadata. If their access has expired (i.e., more than 30 days have passed since their departure), we revoke the session entirely using api.session.revoke().
  3. Role-Based Access Check: For users accessing the HR application, we check if they have the hr role. If they do not have this role:
    • If the user has an active SSO session for other apps, we deny access to HR using api.access.deny() to avoid disrupting the overall session.
    • If the user is not logged into other applications, we fully revoke their session using api.session.revoke() to force them to log in again.
  4. Accounts0 Application: No special restrictions are applied for the Accounts0 app, so it is accessible to both enterprise and non-enterprise users without additional checks.

In this use case, we are utilizing app_metadata.departureDate, but you can use any other metadata available for the user. Alternatively, you can also call your backend systems to verify whether the user still has access via an API. If your use case requires a high level of granularity in authorization logic, we strongly recommend checking out Okta FGA for more advanced capabilities.

Handling SSO Scenarios:

The code differentiates between users benefiting from SSO and those who are logging in for the first time:

  • SSO users: If the user has active SSO sessions, we use api.access.deny() to deny access to the specific application (e.g., HR) without disrupting their overall session.
  • First-time login users: If the user is not logged into any other applications, we use api.session.revoke() to fully terminate the session, ensuring they need to re-authenticate on their next login attempt.

Revoking vs. Denying Access:

  • api.session.revoke(): This fully terminates the user’s session, forcing them to re-enter credentials the next time they try to log in.
  • api.access.deny(): This denies access to the specific transaction or application while keeping the overall session active, allowing the user to access other applications without re-authenticating.

Action 2: Security Check

In this action, we implement different security logic for enterprise and non-enterprise applications to meet the varying security requirements of Travel0 (an enterprise customer) and Accounts0 (used by non-enterprise customers). These requirements ensure that sessions remain secure and that users are authenticated appropriately based on their context.

For enterprise applications (like HR and Payroll), Travel0 has stricter controls. The session must remain tied to the original device and network throughout its duration, and any change in the user's IP address, ASN (Autonomous System Number), or User Agent during the session is treated as a potential security threat. When these changes are detected, we revoke the session to prevent session hijacking or unauthorized access.

For non-enterprise customers using Accounts0, different security logic applies. In this case, we implement Risk-Based Session Timeouts and Geolocation-Based Session Revocation to ensure appropriate session handling. Riskier authentication methods (such as login without MFA) are given shorter session timeouts, while high-risk locations (such as untrusted IP addresses) or impossible travel scenarios trigger session revocation.

The following code demonstrates how we apply these security checks for both enterprise and non-enterprise customers.

    /**
     * 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) => {

      // Current time
      let currentTime = new Date().getTime();

      // for B2B, enterprise customers we have an extra check for device integrity
      if(event.organization){
         // Access session device information
        const initialDevice = event.session?.device || {};
        const currentIP = event.request.ip;
        const currentASN = event.request.asn;
        const currentUserAgent = event.request.user_agent;

        // Compare initial IP and ASN with current session values
        if (initialDevice.initial_ip && initialDevice.initial_ip !== currentIP) {
          // Revoke session if IP changes
          api.session.revoke('IP address mismatch - potential session hijacking');
          return;
        }

        if (initialDevice.initial_asn && initialDevice.initial_asn !== currentASN) {
          // Revoke session if ASN changes
          api.session.revoke('ASN mismatch - potential network change');
          return;
        }

        // Compare the initial user agent with current one
        if (initialDevice.initial_user_agent && initialDevice.initial_user_agent !== currentUserAgent) {
          // Revoke session if User Agent changes
          api.session.revoke('User Agent mismatch - potential device change');
          return;
        }
      } else {
        // Risk-Based Session Timeout: Set shorter timeouts for weaker authentication methods
        const isUsingMFA = event.authentication?.methods?.some(method => method.name === 'mfa');

        if (!isUsingMFA) {
          // Weaker authentication factor detected (e.g., username/password), apply reduced timeouts
          const weakerFactorIdleTimeout = 10 * 60 * 1000; // 10 minutes
          const weakerFactorAbsoluteTimeout = 12 * 60 * 60 * 1000; // 12 hours
          console.log("Applying weaker factor timeouts:", weakerFactorIdleTimeout, weakerFactorAbsoluteTimeout);
          api.session.setIdleExpiresAt(currentTime + weakerFactorIdleTimeout);
          api.session.setExpiresAt(currentTime + weakerFactorAbsoluteTimeout);
        }

        // Geolocation-Based Session Revocation: Check if the login is from a high-risk location

        // Map risk assessment confidence levels to numeric values for comparison
        const riskLevelMapping = {
          "low": 1,
          "neutral": 2,
          "medium": 3,
          "high": 4
        };

        const riskAssessment = event.authentication?.riskAssessment;
        const untrustedIP = riskAssessment?.assessments?.UntrustedIP?.confidence;
        const impossibleTravel = riskAssessment?.assessments?.ImpossibleTravel?.confidence;

        const untrustedIPRiskLevel = riskLevelMapping[untrustedIP] || 0;
        const impossibleTravelRiskLevel = riskLevelMapping[impossibleTravel] || 0;

        if (untrustedIPRiskLevel < 3) {
          // Revoke session if the IP is flagged as high-risk or medium-risk
          api.session.revoke('Untrusted IP address detected');
          return;
        }

        if (impossibleTravelRiskLevel < 3) {
          // Revoke session if impossible travel is detected with medium or high-risk
          api.session.revoke('Impossible travel detected');
          return;
        }
      }
    };

In this action, we apply different security mechanisms based on whether the user is accessing an enterprise or non-enterprise application:

Enterprise Applications (e.g., HR, Payroll):

  • IP Address Mismatch: If the user’s current IP address differs from the original IP when the session started, the session is revoked. This helps prevent session hijacking from different IP addresses.
  • ASN Mismatch: A change in ASN could indicate that the user has switched networks (e.g., using a VPN). If detected, the session is revoked to protect against unauthorized access.
  • User-Agent Mismatch: If the user’s browser or device changes during the session, the session is revoked to prevent potential security breaches.

These checks ensure that Travel0's enterprise users are tightly bound to their original device and network for the entire session, enhancing security.

Non-Enterprise Applications (e.g., Accounts0):

  • Risk-Based Session Timeouts: If a user logs in without MFA, shorter session timeouts are enforced (10 minutes for idle timeout and 12 hours for absolute timeout). This mitigates the risk of using weaker authentication methods.
  • Geolocation-Based Session Revocation: We check for high-risk locations, such as logins from untrusted IP addresses or impossible travel scenarios (logging in from distant locations too quickly). If these are detected, the session is revoked.

Action 3: Session Timeout Configuration

In this action, we will configure session timeouts based on organizational or application-specific requirements. After confirming the user’s access in the previous action, we now need to apply appropriate session timeouts for both idle and absolute session expiration.

We leverage metadata provided at either the organization or client (application) level to configure these timeouts. The action prioritizes organization-level metadata, but if it’s not available, it will fall back to client-level metadata.

This ensures compliance with different security requirements based on the application the user is accessing.

    /**
     * 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) => {
      let currentTime = new Date().getTime();

      // Get organization or client metadata (organization takes precedence if present)
      const metadata = event.organization?.metadata || event.client?.metadata;

      if (metadata) {
        // Set idle timeout
        const idleTimeout = Number(metadata.idle_lifetime);
        if (idleTimeout) {
          console.log("Setting idle timeout:", idleTimeout, currentTime + idleTimeout);
          api.session.setIdleExpiresAt(currentTime + idleTimeout);
        }

        // Set an absolute timeout
        const absoluteTimeout = Number(metadata.absolute_lifetime);
        const createdAt = event.session?.created_at ? new Date(event.session.created_at).getTime() : null;

        if (absoluteTimeout && createdAt) {
          console.log("Setting absolute timeout:", absoluteTimeout, createdAt + absoluteTimeout);
          api.session.setExpiresAt(createdAt + absoluteTimeout);
        }
      }
    };

In this action, we prioritize applying session timeouts from the organization metadata if available. If the organization metadata is not present, we fall back to the client (application) metadata to apply timeouts. Here's how the action works:

  1. Checking for Metadata: The action retrieves the metadata from either the organization (event.organization.metadata) or client (event.client.metadata). If metadata exists, the timeouts are applied accordingly. Organization metadata takes precedence, ensuring that specific organizational security requirements are respected before client-level settings.
  2. Setting Idle Timeout: The idle timeout determines how long a user can remain inactive before their session expires. We calculate the expiration time based on the current time plus the idle timeout value retrieved from the metadata.
    • Example: If the idle_lifetime is set to 15 minutes (900,000 milliseconds), the session will expire 15 minutes after the user becomes idle.
    • Formula: Current Time + Configured Idle Timeout = New Idle Expiration Time
  3. Setting Absolute Timeout: The absolute timeout sets the maximum duration for a session, regardless of activity. This timeout is calculated from the session creation time. We add the configured absolute_lifetime to the time when the session was first created to determine when the session will expire.
    • Example: If the absolute_lifetime is set to 24 hours (86,400,000 milliseconds), the session will expire 24 hours after it was created, regardless of user activity.
    • Formula: Created At + Configured Absolute Timeout = New Absolute Expiration Time

Conclusion

In this blog post, we've explored various use cases that can be addressed with the new features offered by Auth0's Continuous Session Protection. From SaaS applications like BizSuite0 to e-commerce platforms and beyond, these features provide the flexibility and security required to meet a wide range of requirements.

As we mentioned at the beginning, these features are part of a larger building block that will continue to evolve. We are committed to adding more capabilities to enhance Continuous Session Protection, providing developers with even greater control over session management and security.

Enjoy building with these powerful new tools!

  • Twitter icon
  • LinkedIn icon
  • Faceboook icon