JWT Populate Lambda

On this page

To add or change claims in a JWT, assign a lambda in the JWT configuration. FusionAuth runs the lambda before FusionAuth signs the token and issues the token to the user.

Here's a brief video showing how to set up a JWT populate lambda:

Play

When you create a lambda in the Admin UI, FusionAuth provides an empty function for you to implement.

FusionAuth doesn't run this lambda when you call the Login APIThe FusionAuth API that logs a user in without the hosted login pages. directly and omit the applicationId request parameter.

Lambda Structure#

When you create the lambda with the API, give the function the following signature:

function populate(jwt, user, registration, context) {
  // Lambda code goes here
}

The lambda must contain a function named populate that accepts the following parameters:

  • jwt: the claims object that FusionAuth signs and returns as the JWT payload. You can modify this object.
  • user: the FusionAuth User object. This object is read-only.
  • registration: the FusionAuth UserRegistration object. This parameter is null when the user is not registered for the application. This object is read-only.
  • context: Available since 1.59.0 an object containing the context of the request, including access to secrets. This object is read-only.

The jwt Object#

You can add or change any claim in the jwt object, except the header and the reserved claims. When adding a custom claim to the JWT, always use a namespace to avoid clashes with future standard or FusionAuth-specific claims. To remove a claim, set the claim to null. Deleting a claim with delete has no effect.

FusionAuth discards changes to the following reserved claims:

  • act: Available since 1.70.0 the actor claim chain, which token exchangeAn OAuth 2.0 grant type enabling security token exchange, delegation, and impersonation across services. manages
  • amr
  • auth_time
  • authenticationType
  • cnf
  • fa_uid
  • gty
  • iat
  • sub
  • tid
  • tty

FusionAuth discards changes to reserved claims without an error or a log entry, and you can't turn off this behavior. To confirm the claims in a token, decode the issued token.

Before version 1.70.0, a lambda could set act. If a lambda sets a custom act claim, rename the claim with a namespace.

Starting in version 1.59.0, you can lower the exp claim to shorten the lifetime of the token. FusionAuth caps exp at the lifetime configured for the application, so a lambda can't extend the lifetime. You can't remove exp. FusionAuth keeps the original value when you set exp to null. A shorter lifetime helps when one FusionAuth application issues tokens for several contexts. For example, the requested scopes in context.scopes can tell the lambda to issue a short-lived token.

The authenticationType claim holds the authentication method, such as PASSWORD, REFRESH_TOKEN, PASSWORDLESS, or JWT_SSO. Read jwt.authenticationType to change the claims by login method.

The user and registration Objects#

The User API and Registration API documentation describe the user and registration objects. For the claims in the JWT payload, see OpenID Connect & OAuth 2.0 Token.

The context Object#

The read-only context object has the following fields:

  • application: Available since 1.70.2 the Application that FusionAuth issues the token for, without the client secret.
  • scopes: Available since 1.59.0 the scopes requested for the token. The array is empty when the token comes from the Login API.
  • services: Available since 1.64.0 access to secrets through context.services.secrets.get('<secret-name>').

Assigning the Lambda#

After you create the lambda, assign the lambda to an Application on the JWT tab of the Application configuration.

Example Lambdas#

Map Roles to Permissions#

The following lambda turns the user's roles for the application into a permissions claim. The lambda also adds the plan from user.data as a namespaced claim. A resource serverThe API or service that accepts access tokens and returns protected data. A resource server validates each access token before responding. can then check one permission instead of knowing every role:

A lambda that maps roles to permissions.
// maps application roles to permissions, and adds the user's plan as a namespaced claim
var permissionsByRole = {
  admin: ['reports:read', 'reports:write', 'users:manage'],
  editor: ['reports:read', 'reports:write'],
  user: ['reports:read']
};

function populate(jwt, user, registration, context) {
  var roles = registration && registration.roles ? registration.roles : [];
  var permissions = [];
  roles.forEach(function (role) {
    (permissionsByRole[role] || []).forEach(function (permission) {
      if (permissions.indexOf(permission) === -1) {
        permissions.push(permission);
      }
    });
  });

  jwt.permissions = permissions;
  jwt['https://example.com/plan'] = user.data.plan || 'free';
}

Shorten Admin Tokens#

The following lambda limits access tokens for users with the admin role to 15 minutes. The lambda also removes the roles claim when the user has no roles, by setting the claim to null:

A lambda that shortens admin tokens and removes an empty roles claim.
// limits admin access tokens to 15 minutes, and removes the roles claim when the user has no roles
function populate(jwt, user, registration, context) {
  if (!jwt.roles || jwt.roles.length === 0) {
    jwt.roles = null;
    return;
  }

  if (jwt.roles.indexOf('admin') !== -1) {
    jwt.exp = Math.min(jwt.exp, jwt.iat + 15 * 60);
  }
}

For a lambda that calls the FusionAuth API to add group names, see Making API Calls From Lambdas.