Error Handling Best Practices

Error conditions returned from API calls must be handled and processed in an appropriate manner. Failure to do so can lead to unhandled exception situations, resulting in premature termination of pipeline execution and ultimately in an authentication error being returned.

Send error logs to an external service

We recommend sending error event logs to an external service to provide better visibility and diagnosis of anomalous operation. To retain and analyze your log events past the log retention period offered for your subscription plan, use Auth0 log streaming. You can use services like DataDog and AWS EventBridge. We also offer the ability to send logs to an external service with extensions and rules.

Use error objects in rules

There are time constraints regarding how much time a rule has to execute. To learn more, read Custom Database Action Script Execution Best Practices. If recovery from an error condition is not possible (or probable) within this time period, then an error condition should be explicitly returned; this is as simple as completing rule execution by returning an instance of a Node Error object, as in:

return callback(new Error('some description'));

To learn more, read Class: Error on nodejs.org.

Alternatively, an instance of the Auth0-specific UnauthorizedError can be returned, which causes an unauthorized error condition with the supplied error description to be returned to the application that initiated authentication—that is, the application from which redirect to the /authorize endpoint was initiated. This allows an application to offer conditional retry capability and allows you to implement rules to deny access based on certain conditions:

return callback(new UnauthorizedError('some description'), user, context);

For a description of authentication error conditions in Auth0 see the Auth0 SDK library documentation.

Use meaningful error code descriptions

The UnauthorizedError object only returns the description supplied. To use specific processing for unauthorized error conditions, we recommend that you format your descriptions to include some easily accessible error code information, for example:

'[00043] - my specific error description')

Exception handling

Unexpected error conditions, such as uncaught JavaScript exceptions, can result in the premature termination of pipeline execution, which will ultimately result in an error in authentication being returned.

For situations involving asynchronous operations, you must use a catch handler when using Promise object processing. Promise object processing can also be effective for error handling during non-asynchronous operations. As illustrated below, a Promise object can be used to wrap, say, a synchronous function call, making it easier to implement cascaded error handling via use of promise chaining and the like. To learn more about the Promise object, read Promise in MDN Web Docs. To learn more about promise chaining, read Error Handling with Promises on javascript.info.

return new Promise(function(resolve, reject) {
    jwt.verify(
      token,
      secret,{
      clockTolerance: 5},
      function(err, decoded) {
        if (err) {
          reject(err);
        } else {
          resolve(decoded);
      }
    });
  });

Alternatively, you can use try...catch processing to handle JavaScript exceptions that occur during synchronous operation. To learn more, read try...catch in MDN Web Docs. Setting up this type of exception handling can often incur performance costs, so use it sparingly; rule performance should be as optimal as possible. A more pragmatic approach is to implement processing that prevents exceptions from occurring rather than handling them once they have occurred. To learn more about best practices, see Performance Best Practices.

Avoid uninitialized objects in rules

If you use uninitialized objects, that can cause exceptions. We recommend that you include initialization as part of any declaration where the existence of an object is in question. For example:

user.user_metadata = user.user_metadata || {})

In a rule, taking steps to prevent an exception from occurring in the first place is a best practice and is typically less costly in terms of performance and resource usage than implementing exception handling.

Learn more