Auth0 integration

DataDome Account Protect detects account takeover threats and fake registration and protects you against them

📘

Prerequisites for Account Protect

Account Protect is separate from Bot Protect and is not available on your account by default.
Please contact your account manager to enable it.

This service requires a dedicated API key, which will be available on your dashboard once it is enabled.

Main concepts

Setting up Account Protect on Auth0 will enable us to collect more business data (email, social ID, ...) during login and registration events. We will be able to detect account takeovers and fake account creations.

You can find more insights about our detection on the Account Protect Dashboard.

Installation

Step 1: Configure Auth0 to send successful login events to DataDome Account Protect

  • Connect to the Auth0 Console
  • Go to Actions > Library and click on Create Action > Build from scratch
  • Enter Account Protect - Login for the name, select Login / Post Login for the trigger and Node 22 for the runtime and click on Create
  • Copy and Paste the following code
const axios = require('axios');

/**
 * 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) => {
  // Filter refresh token event to not send these events to Athos
  if (event.request.query?.prompt === 'none' || event.transaction?.protocol === 'oauth2-refresh-token') {
    return;
  }

  const strategy = event.connection?.strategy;
  const isLocalAuth = strategy === 'auth0';
  const authType = isLocalAuth ? 'local' : 'social';
  let socialProvider = undefined;
  if (strategy && !isLocalAuth) {
    switch (strategy) {
      case "facebook":
      case "apple":
      case "twitter":
      case "linkedin":
      case "github":
      case "yahoo":
      case "amazon":
        socialProvider = strategy;
        break;
      case "google-oauth2":
      case "google-apps":
        socialProvider = "google";
        break;
      case "waad":
      case "ad":
      case "adfs":
      case "office365":
      case "windowslive":
      case "yammer":
      case "sharepoint":
        socialProvider = "microsoft";
        break;
      default:
        socialProvider = "other";
        break;
    }
  }

  // Derive the first-factor authentication mode from event.authentication.methods
  const authMethods = event.authentication?.methods ?? [];
  const firstFactor = authMethods.find(m => m.name !== 'mfa');
  let authMode = "other";
  if (firstFactor?.name === 'pwd' || firstFactor?.name == 'passkey') {
    authMode = "password";
  } else if (firstFactor?.name === 'email') {
    authMode = "mail";
  }

  const session = {};
  if (event.session) {
    session.id = event.session.id,
    session.createdAt = event.session.created_at;
  };

  const payload = {
    account: event.user.email ?? event.user.user_id,
    status: "succeeded",
    module: {
      requestTimeMicros: new Date().getTime()*1000,
      name: "Fraud SDK Auth0",
      version: "1.0.0"
    },
    header: {
      addr: event.request.ip,
      method: event.request.method,
      host: event.request.hostname,
      port: 443,
      protocol: "https",
      userAgent: event.request.user_agent,
      clientID: event.client.client_id,
    },
    user: {
      id: event.user.user_id
    },
    authentication: {
      type: authType,
      ...(socialProvider && { socialProvider }),
      ...(authMode && { mode: authMode }),
    },
    accountCreationDate: event.user.created_at,
    session
  };

  const config = {
    headers: {
      'x-api-key': event.secrets.FRAUD_API_KEY,
      'Content-type': 'application/json'
    },
    timeout: 1500,
  };

  try {
    const res = await axios.post('https://account-api.datadome.co/v1/validate/login', payload, config);
    if (res.status === 200 && res.data?.action === 'deny') { // deny login only if return 200 & action = deny.
      // Custom actions
    }
  } catch (error) {
    console.log(error);
  }
};
  • Add a new secrets FRAUD_API_KEY and fill its value with your Account Protect Key available in your Dashboard.

We need to add a dependency to Axios, as we use it as the HTTP client.

  • Click on Add Dependency
  • Enter axios in the name field and click on Create
  • Configuration is now done and you can deploy this new action to your tenant
  • Click on Deploy

Now you have to use the new action (Account Protect - Login) in your authentication pipeline

  • Go to Actions > Flows
  • Click on Login
  • Click on Custom on the right panel and move your action in your pipeline
  • Click on Apply

From now on, you will send all successful logins to DataDome Account Protect.

Step 2: Configure Auth0 to send registration events to DataDome Account Protect

  • Connect to the Auth0 Console
  • Go to Actions > Library and click on Create Action > Build from scratch
  • Enter Account Protect - Registration for the name, select Pro User Registration for the trigger and Node 22 for the runtime and click on Create

  • Copy and Paste the following code

/**
* Handler that will be called during the execution of a PreUserRegistration flow.
*
* @param {Event} event - Details about the context and user that is attempting to register.
* @param {PreUserRegistrationAPI} api - Interface whose methods can be used to change the behavior of the signup.
*/
const axios = require("axios");

exports.onExecutePreUserRegistration = async (event, api) => {
 const strategy = event.connection?.strategy;
  const isLocalAuth = strategy === 'auth0';
  const authType = isLocalAuth ? 'local' : 'social';
  let socialProvider = undefined;
  if (strategy && !isLocalAuth) {
    switch (strategy) {
      case "facebook":
      case "apple":
      case "twitter":
      case "linkedin":
      case "github":
      case "yahoo":
      case "amazon":
        socialProvider = strategy;
        break;
      case "google-oauth2":
      case "google-apps":
        socialProvider = "google";
        break;
      case "waad":
      case "ad":
      case "adfs":
      case "office365":
      case "windowslive":
      case "yammer":
      case "sharepoint":
        socialProvider = "microsoft";
        break;
      default:
        socialProvider = "other";
        break;
    }
  }

  // Derive the first-factor authentication mode from event.authentication.methods
  const authMethods = event.authentication?.methods ?? [];
  const firstFactor = authMethods.find(m => m.name !== 'mfa');
  let authMode = "other";
  if (firstFactor?.name === 'pwd' || firstFactor?.name == 'passkey') {
    authMode = "password";
  } else if (firstFactor?.name === 'email') {
    authMode = "mail";
  }

  const payload = {
    account: event.user.email,
    status: "succeeded",
    module: {
      requestTimeMicros: new Date().getTime()*1000,
      name: "Fraud SDK Auth0",
      version: "1.0.0"
    },
    header: {
      addr: event.request.ip,
      method: event.request.method,
      host: event.request.hostname,
      port: 443,
      protocol: "https",
      userAgent: event.request.user_agent,
      clientID: event.client.client_id,
    },
    user: {
      id: event.user.email,
      email: event.user.email,
      lastName: event.user.family_name,
      firstName: event.user.given_name,
      displayName: event.user.name,
      phone: event.user.phone_number,
      pictureUrls: [event.user.picture],
    },
    authentication: {
      type: authType,
      ...(socialProvider && { socialProvider }),
      ...(authMode && { mode: authMode }),
    }
  };

  const config = {
    headers: {
      'x-api-key': event.secrets.FRAUD_API_KEY,
      'Content-type': 'application/json'
    },
    timeout: 1500,
  };

  try {
    const res = await axios.post('https://account-api.datadome.co/v1/validate/registration', payload, config);
    if (res.status === 200 && res.data?.action === 'deny') { // deny login only if return 200 & action = deny.
      // Custom actions
    }
  } catch (error) {
    console.log(error);
  }
};
  • Add a new secrets FRAUD_API_KEY and fill its value with your Account Protect Key available in your Dashboard.

We need to add a dependency to Axios, as we use it as the HTTP client.

  • Click on Add Dependency
  • Enter axios in the name field and click on Create
  • Configuration is now done and you can deploy this new action to your tenant
  • Click on Deploy

Now you have to use the new action (Account Protect - Registration) in your registration pipeline.

  • Go to Actions > Flows

  • Click on Login

  • Click on Custom on the right panel and move action Account Protect Registration in your pipeline

  • Click on Apply

    From now on, you will send all registrations to DataDome Account Protect.

Step 3: Configure Auth0 to send failed login events to DataDome Account Protect

You need to configure an Auth0 stream to a DataDome webhook.

  • Go to Monitoring > Streams and click on Create Stream
  • Enter the following information
    • Name: Account Protect - Failed Login
    • Payload URL: https://account-api.datadome.co/v1/collect/auth0/log-stream
    • Authorization Token: The Account Protect Key available on your Dashboard
    • Content Type: application/json
    • Content Format:JSON Object
    • Filter by Event Category: Select Login - Failure
      • Don't forget to click on "Apply" to ensure it is taken into account.
  • Click on Save.

From now on, you will send all failed login events to DataDome Account Protect.

How to check failed login events that were not sent to DataDome Account Protect

  • Go to Monitoring > Streams and click on Account Protect - Failed Login
  • Select the Health tab

This will allow you to check the last errors received by the Auth0 webhook.

In the example below, the wrong API key was used:

API Reference

Find below the available properties by events and the Auth0 properties they are linked to.

Login Event

The default values are mapped to the properties provided in the Post-Login event​.

NameDescriptionDefault valuePossible valuesOptional
accountThe unique account identifier used for the login attempt.event.user.emailAny string value.
authentication.modeAuthentication modeDepends of the value of event.authentication.methods.name:
- password if the value is pwd or passkey.
- mail if the value is email
- other for other values
biometric, mail mfa, otp, password, otherYes
authentication.socialProviderAuthentication social providerDepends of the value of event.connection.strategy​.
Find the list of possible values on this API reference.
amazon, apple, facebook, github, google, linkedin, microsoft, twitter, yahoo, otherYes
authentication.typeAuthentication typelocal if the event.connection.strategy is auth0, social otherwiselocal, socialProvider, otherYes
accountTypeDescribe the type of the account.guest, staff,external,partner, customer, merchant, vip, test, otherYes
accountCreationDateDate when account was created.event.user.created_atFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZDYes
customFieldsSee dedicated custom fields section in the FAQ
failReasonReason why the login failedunknownAccount,
wrongPassword ,
expiredPassword,
disabledAccount ,
blockedAccount ,
invalidMfa,
internalBusinessRule,
technicalIssue,
other
partnerIdIdentify the partner using the solution.Any string value.Yes
session.createdAtCreation date of the sessionevent.session.created_atFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZDYes
session.idA unique session identifier from your systemevent.session.idAny string value.Yes
statusThe status of the login attempt.StatusType.SUCCEEDEDStatusType.SUCCEEDED, StatusType.FAILEDYes
user.idA unique customer identifier from your system. It has to be the same for all other event sentuser.user_idAny string value.No

Registration Event

The default values are mapped to the properties provided in the Pre-user-registration event​.

NameDescriptionDefault ValuePossible ValuesOptional
accountThe unique account identifier used for the login attempt.event.user.emailAny string value.No
authentication.modeAuthentication modeDepends of the value of event.authentication.methods.name:
- password if the value is pwd or passkey.
- mail if the value is email
- other for other values
biometric, mail mfa, otp, password, otherYes
authentication.socialProviderAuthentication social providerDepends of the value of event.connection.strategy​.
Find the list of possible values on this API reference.
amazon, apple, facebook, github, google, linkedin, microsoft, twitter, yahoo, otherYes
authentication.typeAuthentication typelocal if the event.connection.strategy is auth0, social otherwiselocal, socialProvider, otherYes
accountTypeDescribe the type of the accountguest, staff,external,partner, customer, merchant, vip, test, otherYes
customFieldsSee dedicated custom fields section in the FAQ
failReasonReason why the registration failedduplicateAccount, invalidMfa, cancelled, internalBusinessRule, technicalIssue, other
partnerIdIdentify the partner using the solution.Any string value.
session.createdAtCreation date of the sessionFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZDYes
session.idA unique session identifier from your systemAny string value.Yes
statusRegistration statusattempted, succeeded, failed
user.address.cityCity of the addressAny string value.Yes
user.address.countryCodeCountry of the addressFormat ISO-3166-1-alpha-2Yes
user.address.line1Line 1 of the addressAny string value.Yes
user.address.line2Line 2 of the addressAny string value.Yes
user.address.regionCodeRegion codeYes
user.address.zipCodeZip codeYes
user.createdAtCreation date of the userFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZDYes
user.descriptionDescription or biography of the userAny string value.Yes
user.displayNameDisplay name of the userevent.user.nameAny string value.Yes
user.emailEmail of the userevent.user.emailValid email addressYes
user.externalUrlsExternal URLs of the userAn array of valid URL address (max 10 items)Yes
user.firstNameFirst name of the userevent.user.given_nameAny string value.Yes
user.idA unique customer identifier from your system. It has to be the same for all other event sentevent.user.emailAny string value.No
user.lastNameLast name of the userevent.user.family_nameAny string value.Yes
user.phonePhone of the userevent.user.phone_numberE.164 format including + and a region code
Example : example +33978787878
Yes
user.pictureUrlsPictures of the userAn array with a single element from event.user.pictureAn array of valid URL address (max 10 items)Yes
user.titleTitle of the usermr, mrs, mxYes
user.dateOfBirthDate of birth of the userFormat ISO 8601 YYYY-MM-DDThh:mm:ssTZD