> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev-docs-ia-custom-database-connections.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Get User Database Action Script and Templates

> The Get User script runs when Auth0 needs to determine the current state of existence of a user.

The Get User script implements the function executed to determine the current state of existence of a user. We recommend naming this function `getUser`.

This script is required for [automatic migration to Auth0](/docs/manage-users/user-migration/configure-automatic-migration-from-your-database), and conditionally required without migration enabled depending on the operations configured for the connection. Auth0 recommends you set permanent `user_id` on the returned user profile to avoid creating duplicate users.

When **Import Users to Auth0** is enabled, the Get User script runs when a user attempts to sign up to check if the user already exists in the external user store.

The Get User script also runs when a user attempts to:

* Change their email address ([Change Email](/docs/authenticate/database-connections/custom-db/templates/change-email) script)
* Log in ([Login](/docs/authenticate/database-connections/custom-db/templates/login) script)
* Change their password ([Change Password](/docs/authenticate/database-connections/custom-db/templates/change-password) script)

When **Import Users to Auth0** is disabled, the Get User script runs when a user attempts to sign up to check if the user already exists in the external user store. If a user already exists in the external user store, it does not execute the Create script.

The Get User script also runs when a user attempts to:

* Sign up ([Create](/docs/authenticate/database-connections/custom-db/templates/create) script)
* Change their email address ([Change Email](/docs/authenticate/database-connections/custom-db/templates/change-email) script)
* Change or reset their password ([Change Password](/docs/authenticate/database-connections/custom-db/templates/change-password) script)

## Get User function

The `getUser` function should:

* Send the user's identifier to the external database's API.
* Return the profile data of the user if the user was found.
* Return an error if there was an issue determining whether the user exists or not.

### Definition

The `getUser` function accepts two parameters and returns a `callback` function:

```js lines theme={null}
getUser(email, callback): function
```

| Parameter  | Type     | Description                                             |
| ---------- | -------- | ------------------------------------------------------- |
| `email`    | String   | The user's email address.                               |
| `callback` | Function | Used to pass error or profile data through the pipeline |

This is a pseudo-JavaScript example of how you could implement the `getUser` function:

```javascript lines expandable theme={null}
function getUser(email, callback) {
  // Send user identifier to external database API
  let options = {
    url: "https://example.com/api/search-users",
    body: {
      email: email
    }
  };

  send(options, (err, profileData) => {
    // Return error in callback if there was an issue finding the user
    if (err) {
      return callback(new Error("Could not determine if user exists or not."));
    } else {
      // Return null in callback if user was not found, return profile data in callback if user was found
      if (!profileData) {
        return callback(null);
      } else {
        let profile = {
          email: profileData.email,
          user_id: profileData.userId
        };

        return callback(null, profile);
      }
    }
  });
}
```

## Callback function

The `callback` function is used to pass user profile data or error data through the pipeline.

### Definition

The `callback` function accepts up to two parameters and returns a function:

```js lines theme={null}
callback(error[,profile]): function
```

| Parameter | Type   | Required | Description                       |
| --------- | ------ | -------- | --------------------------------- |
| `error`   | Object | Required | Contains error data.              |
| `profile` | Object | Optional | Contains the user's profile data. |

### Return the user profile (user found)

<Warning>
  The profile data returned by the Get User script for a user must be consistent with the profile data returned by the Login script.
</Warning>

If the user is found, pass a `null` value to the `error` parameter, and pass the user's profile data to the `profile` parameter in [normalized form](/docs/manage-users/user-accounts/user-profiles/normalized-user-profile-schema):

```js lines theme={null}
return callback(null, {
    username: "username",
    user_id: "my-custom-db|username@domain.com",
    email: "username@domain.com",
    email_verified: false,
    user_metadata: {
        language: "en"
    },
    app_metadata: {
        plan: "full"
    },
    mfa_factors: [
      {
        phone: {
          value: "+15551234567"
        }
      },
    ]
});
```

In addition to the standard fields, you can include the `user_metadata`, `app_metadata`, and `mfa_factors` fields.

### Return no user profile (user not found)

If the user is not found, pass a `null` value to the `error` parameter, and omit the `profile` parameter:

```js lines theme={null}
return callback(null);
```

### Return an error

If an error occurs, pass error data to the `error` parameter with relevant information about what went wrong:

```js lines theme={null}
return callback(new Error("My custom error message."));
```

For more information, read [Troubleshoot Custom Databases](/docs/authenticate/database-connections/custom-db/error-handling).

## Language-specific script examples

Auth0 provides sample scripts for use with the following languages/technologies:

<CodeGroup>
  ```javascript Javascript lines theme={null}
  function getByEmail(email, callback) {
    // This script should retrieve a user profile from your existing database,
    // without authenticating the user.
    // It is used to check if a user exists before executing flows that do not
    // require authentication (signup and password reset).
    //
    // There are three ways this script can finish:
    // 1. A user was successfully found. The profile should be in the following
    // format: https://auth0.com/docs/users/normalized/auth0/normalized-user-profile-schema.
    //     callback(null, profile);
    // 2. A user was not found
    //     callback(null);
    // 3. Something went wrong while trying to reach your database:
    //     callback(new Error("my error message"));
    const msg = 'Please implement the Get User script for this database connection ' +
      'at https://manage.auth0.com/#/connections/database';
    return callback(new Error(msg));
  }
  ```

  ```javascript ASP.NET MVC3 lines expandable theme={null}
  // For ASP.NET Membership Provider (MVC3 - Universal Providers)
  function getByEmail(email, callback) {
    const sqlserver = require('tedious@1.11.0');
    const Connection = sqlserver.Connection;
    const Request = sqlserver.Request;
    const TYPES = sqlserver.TYPES;
    const connection = new Connection({
      userName: 'the username',
      password: 'the password',
      server: 'the server',
      options: {
        database: 'the db name',
        encrypt: true // for Windows Azure
      }
    });
    connection.on('debug', function(text) {
      // if you have connection issues, uncomment this to get more detailed info
      //console.log(text);
    }).on('errorMessage', function(text) {
      // this will show any errors when connecting to the SQL database or with the SQL statements
      console.log(JSON.stringify(text));
    });
    connection.on('connect', function(err) {
      if (err) return callback(err);
      var user = {};
      const query =
        'SELECT Memberships.UserId, Email, Users.UserName ' +
        'FROM Memberships INNER JOIN Users ' +
        'ON Users.UserId = Memberships.UserId ' +
        'WHERE Memberships.Email = @Username OR Users.UserName = @Username';
      const getMembershipQuery = new Request(query, function(err, rowCount) {
        if (err) return callback(err);
        if (rowCount < 1) return callback();
        callback(null, user);
      });
      getMembershipQuery.addParameter('Username', TYPES.VarChar, email);
      getMembershipQuery.on('row', function(fields) {
        user = {
          user_id: fields.UserId.value,
          nickname: fields.UserName.value,
          email: fields.Email.value
        };
      });
      connection.execSql(getMembershipQuery);
    });
  }
  ```

  ```javascript ASP.NET MVC4 lines expandable theme={null}
  // For ASP.NET Membership Provider (MVC4 - Simple Membership)
  function getByEmail(email, callback) {
    const sqlserver = require('tedious@1.11.0');
    const Connection = sqlserver.Connection;
    const Request = sqlserver.Request;
    const TYPES = sqlserver.TYPES;
    const connection = new Connection({
      userName: 'the username',
      password: 'the password',
      server: 'the server',
      options: {
        database: 'the db name',
        encrypt: true // for Windows Azure
      }
    });
    connection.on('debug', function(text) {
      // if you have connection issues, uncomment this to get more detailed info
      //console.log(text);
    }).on('errorMessage', function(text) {
      // this will show any errors when connecting to the SQL database or with the SQL statements
      console.log(JSON.stringify(text));
    });
    connection.on('connect', function(err) {
      if (err) return callback(err);
      var user = {};
      const query =
        'SELECT webpages_Membership.UserId, UserName, UserProfile.UserName from webpages_Membership ' +
        'INNER JOIN UserProfile ON UserProfile.UserId = webpages_Membership.UserId ' +
        'WHERE UserProfile.UserName = @Username';
      const getMembershipQuery = new Request(query, function (err, rowCount) {
        if (err) return callback(err);
        if (rowCount < 1) return callback();
        callback(null, user);
      });
      getMembershipQuery.addParameter('Username', TYPES.VarChar, email);
      getMembershipQuery.on('row', function (fields) {
        user = {
          user_id: fields.UserId.value,
          nickname: fields.UserName.value,
          email: fields.UserName.value
        };
      });
      connection.execSql(getMembershipQuery);
    });
  }
  ```

  ```javascript MongoDB lines theme={null}
  function getByEmail(email, callback) {
    const MongoClient = require('mongodb@5.1.0').MongoClient;
    const client = new MongoClient('mongodb://user:pass@mymongoserver.com');
    client.connect(function (err) {
      if (err) return callback(err);
      const db = client.db('db-name');
      const users = db.collection('users');
      users.findOne({ email: email }, function (err, user) {
        client.close();
        if (err) return callback(err);
        if (!user) return callback(null, null);
        return callback(null, {
          user_id: user._id.toString(),
          nickname: user.nickname,
          email: user.email
        });
      });
    });
  }
  ```

  ```javascript MySQL lines theme={null}
  function getByEmail(email, callback) {
    const mysql = require('mysql');
    const connection = mysql({
      host: 'localhost',
      user: 'me',
      password: 'secret',
      database: 'mydb'
    });
    connection.connect();
    const query = 'SELECT id, nickname, email FROM users WHERE email = ?';
    connection.query(query, [ email ], function(err, results) {
      if (err || results.length === 0) return callback(err || null);
      const user = results[0];
      callback(null, {
        user_id: user.id.toString(),
        nickname: user.nickname,
        email: user.email
      });
    });
  }
  ```

  ```javascript PostgreSQL lines theme={null}
  function loginByEmail(email, callback) {
    //this example uses the "pg" library
    //more info here: https://github.com/brianc/node-postgres
    const postgres = require('pg');
    const conString = 'postgres://user:pass@localhost/mydb';
    postgres.connect(conString, function (err, client, done) {
      if (err) return callback(err);
      const query = 'SELECT id, nickname, email FROM users WHERE email = $1';
      client.query(query, [email], function (err, result) {
        // NOTE: always call `done()` here to close
        // the connection to the database
        done();
        if (err || result.rows.length === 0) return callback(err);
        const user = result.rows[0];
        return callback(null, {
          user_id: user.id,
          nickname: user.nickname,
          email: user.email
        });
      });
    });
  }
  ```

  ```javascript SQL Server lines expandable theme={null}
  function getByEmail(email, callback) {
    //this example uses the "tedious" library
    //more info here: http://pekim.github.io/tedious/index.html
    const sqlserver = require('tedious@1.11.0');
    const Connection = sqlserver.Connection;
    const Request = sqlserver.Request;
    const TYPES = sqlserver.TYPES;
    const connection = new Connection({
      userName:  'test',
      password:  'test',
      server:    'localhost',
      options:  {
        database: 'mydb'
      }
    });
    const query = 'SELECT Id, Nickname, Email FROM dbo.Users WHERE Email = @Email';
    connection.on('debug', function (text) {
      console.log(text);
    }).on('errorMessage', function (text) {
      console.log(JSON.stringify(text, null, 2));
    }).on('infoMessage', function (text) {
      console.log(JSON.stringify(text, null, 2));
    });
    connection.on('connect', function (err) {
      if (err) return callback(err);
      const request = new Request(query, function (err, rowCount, rows) {
        if (err) return callback(err);
        callback(null, {
          user_id: rows[0][0].value,
          nickname: rows[0][1].value,
          email: rows[0][2].value
        });
      });
      request.addParameter('Email', TYPES.VarChar, email);
      connection.execSql(request);
    });
  }
  ```

  ```javascript Azure SQL Database lines theme={null}
  function getByEmail (name, callback) {
    var profile = {
      user_id:     "103547991597142817347",
      nickname:    "johnfoo",
      email:       "johnfoo@gmail.com",
      name:        "John Foo",
      given_name:  "John",
      family_name: "Foo"
    };
    callback(null, profile);
  }
  ```

  ```js Axios lines expandable theme={null}
  async function getUserAsync(email, callback) {
    //should be updated as new versions of axios are made available (https://auth0-extensions.github.io/canirequire/#axios)
    const axios = require("axios@0.22.0");

    let response;

    try {
      response = await axios.post(
        //store API url in connection settings to better support SDLC environments
        configuration.baseAPIUrl + "/getUser",
        //user credentials passed as request body
        {
          email: email,
        },
        {
          timeout: 10000, //end call gracefully if request times out so script can do necessary callback
          headers: {
            //securing api call with apiKey stored in connection settings.
            //quick and easy approach however using M2M tokens is more secure as
            // a secret must not be shared between client and API.
            "x-api-key": configuration.apiKey,
          },
        }
      );
    } catch (e) {
      if (e.response.status === 404) {
        //assuming api returns 404 when no user with specified email/username found
        return callback(null, null);
      }
      //callback for any other error type
      return callback(new Error(e.message));
    }

    try {
      let user = response.data;

      //if using multiple custom db connections in your tenant prefix the
      //user_id with a connection specific key ex: "connName|" + user.user_id
      //this ensures unique user ids across all db connections
      return callback(null, {
        user_id: user.user_id,
        email: user.email,
      });
    } catch (e) {
      return callback(new Error(e.message));
    }
  }
  ```

  ```javascript Stormpath lines expandable theme={null}
  function getByEmail(email, callback) {
    // Replace the {yourStormpathClientId} with your Stormpath ID
    var url = 'https://api.stormpath.com/v1/applications/{yourStormpathClientId}/accounts';
    // Add your Stormpath API Client ID and Secret
    var apiCredentials = {
      user : '{yourStormpathApiId}',
      password: '{yourStormpathApiSecret}'
    };
    // Make a GET request to find a user by email
    request({
      url: url,
      method: 'GET',
      auth: apiCredentials,
      qs: { q: email },
      json: true
    }, function (error, response, body) {
      if (response.statusCode !== 200) return callback();
      var user = body.items[0];
      if (!user) return callback();
      var id = user.href.replace('https://api.stormpath.com/v1/accounts/', '');
      return callback(null, {
        user_id: id,
        username: user.username,
        email: user.email,
        email_verified: true
        // Add any additional fields you would like to carry over from Stormpath
      });
    });
  }
  ```
</CodeGroup>
