Lambdas Overview

Overview

A FusionAuth lambda is a JavaScript function that can be used to augment or modify runtime behavior, typically during a login flow.

FusionAuth leverages lambdas to handle different events that occur inside it as well as customize tokens and messages that FusionAuth sends such as JWTs or SAML responses. A lambda may optionally be invoked when these events occur. Developers can write lambdas in the FusionAuth UI or can upload lambdas via the API.

Here’s a brief video covering some aspects of lambdas:

Lambda Types

Lambdas are typed according to their intended purpose. You cannot use a lambda intended for one situation in another.

The following lambdas are currently supported:

Example Lambdas

Each lambda documentation page will have an example lambda implementation specific to that functionality. The signature of each lambda function differs for different types of lambdas.

Adding Claims

Here is an example of a FusionAuth lambda that adds additional claims to a JWT:

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

Using Lambda HTTP Connect

This feature allows you to make HTTP requests from within a lambda.

FusionAuth Reactor logo

This feature is only available in an Essentials or Enterprise plan. Please visit our pricing page to learn more.

Here is a FusionAuth lambda that adds additional claims to a JWT based on an HTTP request:

A lambda which adds claims based on an external API.

function populate(jwt, user, registration) {
  var response = fetch("https://api.example.com/api/status?" + user.id, {
    method: "GET",
    headers: {
      "Content-Type": "application/json"
    }
  });

  if (response.status === 200) {
    // assuming successful response looks like:
    // {"status":"statusValue"}
    var jsonResponse = JSON.parse(response.body);
    jwt.status = jsonResponse.status;
  } else {
    jwt.status = "basic";
  }
}

You can also call FusionAuth APIs with a valid API key:

A lambda which adds claims based on a FusionAuth API.

function populate(jwt, user, registration) {
  var response = fetch("http://localhost:9012/api/group", {
    method: "GET",
    headers: {
      "Authorization": "bf69486b-4733-4470-a592-f1bfce7af580"
    }
  });

  if (response.status === 200) {
    // a successful response as defined in the Groups API
    var jsonResponse = JSON.parse(response.body);
    jwt.groups = jsonResponse.groups;
  } else {
    jwt.groups = [];
  }
}

Use port 9012, or the configured value for fusionauth-app.http-local.port, whenever making a FusionAuth API call in a lambda. Doing so minimizes network traffic contention and improves performance.

Here’s a video showing more details about Lambda HTTP Connect:

Headers

You can provide request header values in a number of different ways:

An anonymous object

headers: {
  "Content-Type": "application/json"
}

A hash or map

headers: new Headers({
   "Content-Type": "application/json"
})

An array

headers: new Headers([
    ["Content-Type", "application/json"]
])

Response

A response object will be returned. It will have the following fields:

headersObject

The headers returned by the response. The keys of this object are the header names. All header keys are lower cased.

statusInteger

The HTTP status code.

bodyString

The body of the response.

JavaScript

Engine

GraalJS

GraalJS is built on top of the Java virtual machine. For security reasons, FusionAuth restricts access to various GraalJS features during a lambda invocation.

The GraalJS Engine supports ECMAScript 2021.

Here is documentation for the GraalJS engine:

This engine has been available since version 1.35.0.

Nashorn

As of version 1.49 the Nashorn engine has been removed. Upgrading to version 1.49.0 or beyond will migrate existing lambdas to GraalJS.

Nashorn is built on top of the Java virtual machine and while Nashorn permits access to the Java API, for security reasons FusionAuth restricts access to all Java objects during a lambda invocation. Here is the documentation provided by Oracle for the Nashorn engine:

The Nashorn engine supports ECMAScript version 5.1.

Console

In addition to the standard JavaScript objects and constructs, FusionAuth provides the console object to allow you to create entries in the Event Log during a lambda invocation.

Available methods:

  • info - Create an event log of type Information
  • log - alias to the info method
  • debug - Create an event log of type Debug (only when the Lambda has enabled Debug)
  • error - Create an event log of type Error

The log, info and error will always cause Event Log entries to be created as a result of the lambda invocation. The log method is an alias to the info method. Messages created using the debug method will only be added to the Event Log when you have enabled Debug in your lambda configuration.

Messages of each type are accumulated during the lambda invocation and a maximum of one event log of each type will be created as a result of the lambda invocation. This means making multiple requests to console.info in the lambda function body will result in a single event log of type Information.

When logging objects, you’ll need to stringify them to see their data.

function populate(jwt, user, registration) {
  //...
  console.log(user); // doesn't log any data other than the fact a user is an object. Probably not what you want.
  console.log(JSON.stringify(user)); // outputs all the properties of the user object.
  console.log(JSON.stringify(user, null, ' ')); // pretty prints the user object.
  //...
}

Exceptions

Any exception thrown in a lambda does two things:

  • write an event log entry
  • exit the lambda code path

What that means for the overall user experience depends on the type of lambda. For example, for a JWT populate lambda, the JWT will not be modified. For a reconcile lambda, the user will not be created or linked.

In general, exceptions should not be used for flow control and should instead be used for exceptional situations.

To view exception details, enable debugging on the lambda via the Debug enabled toggle in the administrative user interface or the API.

Limitations

If the Identity Provider linking strategy is set to Link Anonymously, no lambdas will be used by FusionAuth. More information about the Identity Provider linking strategies is available here.

The FusionAuth lambdas do not have full access to JavaScript modules and libraries. They also cannot import, require or load other libraries currently. These features might be added to our lambda support in the future.

console.log and other console methods only take one argument; this differs from the console method available in web browsers.

Lambda HTTP Connect Limitations

FusionAuth Reactor logo

This feature is only available in an Essentials or Enterprise plan. Please visit our pricing page to learn more.

When using Lambda HTTP Connect to make HTTP requests, do not call a FusionAuth API which invokes the calling lambda, because it will fail. For example, in a JWT Populate lambda, do not invoke the Login API.

Requests from a lambda require the lambda to use the GraalJS engine. HTTP requests will time out after two seconds.

The fetch method in a lambda does not implement the entire fetch API as implemented in a browser. The first argument to fetch must always be a string URL. Only the following options are supported:

  • method, which defaults to GET
  • headers, which defaults to null
  • body, which must be a string

Managing Lambdas

You can use the FusionAuth APIs, client libraries or the CLI tool to manage your lambdas.

It’s recommended you keep your lambdas under version control as they are part of the code execution path of FusionAuth.

You can test your lambdas as well.