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.
Asynchronous features
Asynchronous features of JavaScript, including Promise objects and async functions, 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 if the external service or API cannot be reached.
Examples
Auth0 supports using Promise objects and async functions 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.
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}`));
});
}
Was this helpful?
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.
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);
}
Was this helpful?
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.
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.
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.
Error handling
Pass an Error
object to the callback
function with a descriptive message of the error:
return callback(new Error('My custom error message'));
Was this helpful?
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 through Auth0, and create an Action 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 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:
{
"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
}
Was this helpful?
If you want to retrieve either of these properties with the Auth0 Management API, include the read:user_idp_tokens
scope when requesting an Access Token.