> ## Documentation Index
> Fetch the complete documentation index at: https://auth0-actions-triggers-prototype.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Learn about best practices for custom database action script execution.

# Custom Database Action Script Execution Best Practices

A custom database connection type allows you to configure action scripts, which contain custom code Auth0 uses to interface with your legacy identity store. Action scripts are a named JavaScript function that accepts a predefined set of parameters.

## Webtask containers

Action scripts execute within an individual Webtask container with an execution limit of approximately 20 seconds. After the functions execute, the container is recycled.

When a container is recycled, it terminates the action script’s pending operations. This may result in an error condition being returned and a potential reset of the `global` object. For more information on the `global` object, read [Custom Database Action Script Environment Best Practices](/docs/authenticate/database-connections/custom-db/custom-database-connections-scripts/environment).

## Asynchronous features

Asynchronous features of JavaScript, including [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) objects and [async functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function), are supported in action scripts.

You can use asynchronous features to execute non-blocking operations within an action script, but make sure that these operations do not exceed the execution limit of the Webtask container. When the Webtask container is recycled, it will terminate any pending operations, which may result in unexpected behavior or an error.

If you are making a call to an external service or API within your action script, set the function to time out after a reasonable duration, and [return an error](#error-handling) if the external service or API cannot be reached.

### Examples

Auth0 supports using [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) objects and [async functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) within action scripts.

#### Promise object

This example uses the built-in JavaScript `fetch` method, which gets a resource from a network then returns a Promise object, written using [promise chains](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#chaining).

```javascript lines expandable theme={null}
function login(userNameOrEmail, password, callback) {
	const hashedPassword = hash(password);
	const apiEndpoint = 'https://example.com/api/authenticate';
	const options = {
		method: 'POST',
		body: {
			email: userNameOrEmail,
			password: hashedPassword
		}
	};

	fetch(apiEndpoint, options) 
		.then((response) => {
			if (!response.ok) {
				return callback(new Error(`HTTP error! Status: ${response.status}`));
			}

			return response.json();
		})
		.then((response) => {
			if (response.err) {
				return callback(new Error(`Error authenticating user: ${err}`));
			}

			let profile = {
				email: response.profileData.email,
				username: response.profileData.username
			};

			return callback(null, profile);
		})
		.catch((err) => {
			return callback(new Error(`An error occurred: ${err}`));
		});
  }
```

#### Async function

This example uses the built-in JavaScript `fetch` method, which gets a resource from a network then returns a Promise object, written using [async functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function).

```js lines expandable theme={null}
async function login(userNameOrEmail, password, callback) {
	const hashedPassword = hash(password);
	const apiEndpoint = 'https://example.com/api/authenticate';
	const options = {
		method: 'POST',
		body: {
			email: userNameOrEmail,
			password: hashedPassword
		}
	};

	const response = await fetch(apiEndpoint, options);

	if (!response.ok) {
		return callback(new Error(`HTTP error! Status: ${response.status}`));
	}

	const result = response.json();

	if (result.err) {
		return callback(new Error(`Error authenticating user: ${err}`));
	}

	let profile = {
		email: response.profileData.email,
		username: response.profileData.username
	};

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

## Callback function

The `callback` function signals the action script’s operation is complete and must be called exactly once. An action script should complete immediately after a call to the `callback` function, preferably by explicitly using the `return` statement.

<Warning>
  If the `callback` function is called more than once, then it may lead to unexpected results and/or errors.

  If the `callback` function is not called at all, then execution of the action script will stall, and an error will be returned when the Webtask container is recycled.
</Warning>

### Asynchronous processing

If an action script uses asynchronous processing, then the `callback` function must be called after all asynchronous operations complete.

### Parameters

If the `callback` function is called with no parameters, it will be executed as if a `null` parameter had been provided.

## Size

The total size of implementation for any action script must not exceed 100kB. This size limitation excludes imported `npm` modules. For more information on `npm` modules, read [Custom Database Action Script Environment Best Practices](/docs/authenticate/database-connections/custom-db/custom-database-connections-scripts/environment).

The larger the size of a script, the more latency is introduced based on the packaging and transport process employed by the Webtask platform. The size impacts the performance of the system.

## Anonymous functions

Action scripts can be implemented as anonymous functions, but it is not recommended that you do so. Anonymous functions make it difficult to debug the action script and interpret the call-stack generated as a result of any exceptional error condition. To learn more about anonymous functions, read [IIFE on MDN Web Docs](https://developer.mozilla.org/en-US/docs/Glossary/IIFE).

## Error handling

Pass an `Error` object to the `callback` function with a descriptive message of the error:

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

## Security

### Database interface vs. API

Ensure to secure all communications between Auth0 and your legacy identity store. If your legacy identity store does not already have an API implemented, it is highly recommended that you do so.

If your legacy identity store has an API available, you can [register the API](/docs/get-started/auth0-overview/set-up-apis) through Auth0, and [create an Action](/docs/manage-users/access-control/sample-use-cases-actions-with-authorization#deny-access-to-anyone-calling-an-api) to restrict access from end users.

If your legacy identity store does not have an API available—and implementing one is not feasible—you can still communicate with your database directly. Make sure to [add Auth0 IP addresses to your firewall’s allow list](/docs/secure/security-guidance/data-security/allowlist) to allow inbound traffic from Auth0.

## Identity provider tokens

If the `user` object returns the `access_token` and `refresh_token` properties, Auth0 handles them differently from other types of user information. Auth0 stores them in the `user` object's `identities` property:

```json lines theme={null}
{
	"email": "you@example.com",
	"updated_at": "2019-03-15T15:56:44.577Z",
	"user_id": "auth0|some_unique_id",
	"nickname": "a_nick_name",
	"identities": [ 
		{
			"user_id": "some_unique_id",
			"access_token": "e1b5.................92ba",
			"refresh_token": "a90c.................620b",
			"provider": "auth0", 
			"connection": "custom_db_name",
			"isSocial": false 
		}
  ], 
  "created_at": "2019-03-15T15:56:44.577Z",
  "last_ip": "192.168.1.1",
  "last_login": "2019-03-15T15:56:44.576Z",
  "logins_count": 3
}
```

If you want to retrieve either of these properties with the Auth0 <Tooltip tip="Management API: A product to allow customers to perform administrative tasks." cta="View Glossary" href="/docs/glossary?term=Management+API">Management API</Tooltip>, include the `read:user_idp_tokens` scope when [requesting an Access Token](/docs/secure/tokens/access-tokens/management-api-access-tokens/get-management-api-access-tokens-for-production).
