Lambdas

On this page

In FusionAuth, a lambda is a JavaScript function that can augment or modify behavior during authentication or authorization. For example, the following lambda adds claims to a JWT:

function populate(jwt, user, registration) {
  jwt.favoriteColor = user.data.favoriteColor;
  jwt.applicationBackgroundColor = registration.data.backgroundColor;
}

FusionAuth runs a lambda at a set point in a flow, such as when FusionAuth issues a token, links a user from an identity provider, or validates a login. Each lambda type has one such point. Lambdas customize tokens and responses, such as JWTs and SAML responses, and add custom logic to logins and registrations.

Lambdas can't import, require, or load JavaScript modules and libraries. This page explains the objects and methods FusionAuth provides to lambdas.

This brief video provides an overview of lambdas:

Play

Console#

The console object creates entries in the Event Log during a lambda invocation. A lambda console method accepts several arguments. Unlike the browser console object, the method joins the arguments with no separator.

The console object provides the following log methods:

  • info(): creates an Event Log entry of type Information.
  • log(): an alias for info().
  • error(): creates an Event Log entry of type Error.
  • debug(): creates an Event Log entry of type Debug, only when you turn on Enable debug logging for the lambda.

The lambda has no console.warn() or console.trace() method. Calling a missing method throws an exception.

Messages accumulate during a lambda invocation, and FusionAuth creates at most one Event Log entry of each type. For instance, several calls to console.info in one invocation create a single Information entry that holds all the messages.

The Event Log shows an object in a compact form, such as {plan: "pro", department: "Engineering"}, and an array with the array length, such as (1)["user"]. To print an object as JSON, call JSON.stringify():

function populate(jwt, user, registration, context) {
  // logs "Roles: (1)["user"]"
  console.info('Roles: ', registration.roles);
  // logs "Data: {"plan":"pro","department":"Engineering"}"
  console.info('Data: ' + JSON.stringify(user.data));
}

HTTP Connect#

Essentials plan required

This feature requires at least an Essentials plan.

Lambda HTTP Connect makes HTTP requests from within a lambda.

For instance, the following lambda adds a claim to a JWT from an external billing API. The lambda reads the API key from a secret. When the API fails, the lambda logs an error and adds a default value:

A lambda that adds a claim from an external API.
// adds the user's subscription tier from a billing API, and falls back to basic when the API fails
function populate(jwt, user, registration, context) {
  var response = fetch('https://billing.example.com/api/customers/' + encodeURIComponent(user.id), {
    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'Authorization': 'Bearer ' + context.services.secrets.get('billing-api-key')
    },
    connectTimeout: 1000,
    readTimeout: 1500
  });

  // a status of -1 means FusionAuth could not reach the API
  if (response.status !== 200) {
    console.error('Could not read the billing tier for user ' + user.id + '. The billing API returned status ' + response.status + '.');
    jwt['https://example.com/tier'] = 'basic';
    return;
  }

  jwt['https://example.com/tier'] = JSON.parse(response.body).tier || 'basic';
}

For more information, see the Lambda HTTP Connect documentation.

Secrets#

Available since 1.64.0

Lambda secrets help you securely store secret values used in lambdas, like API keys and application passwords.

  1. In the Admin UI, visit Settings -> Key Master .
  2. From the dropdown in the upper right, select Import Secret .
  3. Enter a unique Name. A lambda reads the secret by this name.
  4. Enter the Secret value.

To access secrets, use the context parameter. Pass a secret name to context.services.secrets.get('<secret-name>') to retrieve the secret value as a string. The method returns null when no secret has the name:

var apiKey = context.services.secrets.get('billing-api-key');

The HTTP Connect example sends a secret as an API key. Never log a secret value.

Exceptions#

When a lambda throws an exception, FusionAuth writes an Error entry with the exception message to the Event Log. FusionAuth writes the entry whether or not debugging is enabled for the lambda. FusionAuth also discards every change the lambda made to its arguments before the exception.

What happens next depends on the lambda type:

  • JWT populate, client credentials JWT populate, and UserInfo populate: FusionAuth issues the token or the UserInfo response without the lambda's changes.
  • Login validation: the login continues, so a lambda that throws doesn't block the user. To block a login, set an error on result instead.
  • MFA requirement: FusionAuth requires MFA.
  • Self-service registration validation: FusionAuth blocks the registration with a general error.
  • CIMDAn OAuth 2.0 extension in which the client identifier is an HTTPS URL that hosts a JSON document describing the client's metadata. The authorization server retrieves the metadata from the URL instead of requiring a Dynamic Client Registration request. client registration: FusionAuth rejects the client.
  • Token exchangeAn OAuth 2.0 grant type enabling security token exchange, delegation, and impersonation across services. policy: FusionAuth denies the exchange.
  • Token exchange populate: the token exchange request fails with a server_error.
  • Reconcile, including the LDAP connector: the login fails, and FusionAuth doesn't create or link the user.
  • SAML v2 populate: FusionAuth shows an error page instead of sending the SAML response.
  • SCIMAn open standard defining an HTTP REST protocol and schema for automating user and group provisioning across systems. converters: the SCIM request fails.

Catch errors you expect, such as a failed fetch() call, and handle them in the lambda. Reserve exceptions for errors the lambda can't handle.

To write your own diagnostic output to the Event Log, use console.info or console.error. FusionAuth writes console.debug output only when you turn on Enable debug logging for the lambda in the Admin UI, or set lambda.debug with the API.

Managing Lambdas#

Use the FusionAuth APIs, client libraries, or the CLI tool to manage lambdas.

Lambdas are part of your authentication and authorization logic, so test your lambdas and track changes to lambdas in version control.

Engine#

GraalJS#

GraalJS is built on top of the Java virtual machine. For security reasons, FusionAuth restricts access to various GraalJS features within lambdas.

Starting in FusionAuth 1.56.0, lambdas run on GraalJS 24.1, which supports ECMAScript 2024. You can use features such as Object.groupBy, Array.prototype.toSorted, and String.prototype.replaceAll. Earlier versions of FusionAuth use GraalJS 22.3, which supports ECMAScript 2022.

For more information, see the GraalJS engine documentation.

GraalJS has been available since FusionAuth 1.35.0.

Lambda Types#

Each lambda has a type, which sets when FusionAuth runs the lambda and which arguments the lambda receives.

FusionAuth supports the following lambda types. For examples and details, see the linked pages: