OpenID Connect Reconcile Lambda

When an OpenID Connect identity provider is used to complete a federated login request, FusionAuth will use the configured linking strategy and well known OpenID Connect claims to reconcile the user. FusionAuth will attempt to match the user information returned from the OpenID Connect identity provider to an existing user account or create a new one.

You may optionally utilize a lambda to customize the user and user registration during the authentication event.

It is common that the claims returned from the UserInfo endpoint during an OpenID Connect login request will contain custom claims defined by your identity provider. In order to utilize these custom claims you may wish to use a lambda to assist FusionAuth during the login request to copy these claims to appropriate fields on the FusionAuth user object.

When you create a new lambda using the FusionAuth administrative user interface, you will be provided an empty function to implement.

Lambda Structure

If you are using the API to create the lambda you will need to ensure your function has the following signature:

function reconcile(user, registration, jwt, id_token, tokens) {
  // Lambda code goes here
}

This lambda must contain a function named reconcile that takes at least three parameters, the fourth and fifth parameters are optional. The parameters that the lambda is passed are:

  • user - the FusionAuth User object. You can modify this, except the email or username attribute may not be modified after the user has been linked.
  • registration - the FusionAuth UserRegistration object. You can modify this.
  • jwt - the JSON payload returned from the OpenID Connect UserInfo endpoint. This is read-only.
  • id_token - the JSON payload returned in the id_token when available. This parameter may not be provided and will be undefined in that case. This is read-only. Available since 1.31.0
  • tokens - an object containing the encoded versions of the access_token and optionally the id_token when available. This is read-only. Available since 1.48.0

The two FusionAuth objects are well documented in the User API and Registration API documentation.

The jwt object contains the payload from the UserInfo endpoint. It may contain well known OpenID Connect registered claims as well as any custom claims defined by the Identity Provider.

The id_token will be provided to the Lambda only when it was returned by the IdP and the signature can be verified. The id_token will be returned by the Identity Provider when the openid scope was requested.

The signature can be verified in one of two ways:

  • The token has been signed using the client_secret and an HMAC algorithm.
  • The token has been signed using an asymmetric key-pair and the public key used to verify the signature has been published using the JSON Web Key Set (JWKS) and is correctly advertised by the jwks_uri in the .well-known/openid-configuration discovery document. In order for FusionAuth to correctly resolve this public key, you must configure the IdP using the Issuer and allow FusionAuth to discover the OpenID Connect configuration using the OpenID Connect discovery document. If you manually configure the Authorize, Token and UserInfo endpoints, automatic discovery of the JSON Web Key Set URI will not occur.

Please note that prior to version 1.48.0, this parameter was only available if it had been signed with the client_secret using an HMAC algorithm.

The tokens parameter will always be present and will contain the encoded version of the access_token. When the id_token is present and the signature has been verified, this object will also contain the id_token in the encoded form. These tokens may be useful if you need to use the HTTP Lambda Connect feature to make an external API call using either of these tokens.

Assigning The Lambda

Once a lambda is created, you may assign it to one or more OpenID Connect IdPs in the IdP configuration.

Navigate to Settings -> Identity Providers and select your existing an OpenID Connect configuration or click Add provider and select OpenID Connect if it has not yet been configured.

Example Lambda

Here is an example of a simple Lambda that assists FusionAuth to reconcile the User from a successful GitHub login request.

function reconcile(user, registration, jwt, id_token, tokens) {
  // This is an example lambda function reconcile the GitHub login

  // Set GitHub Avatar URL to the FusionAuth imageURL
  user.imageUrl = jwt.avatar_url;

  // Update the registration username to the GitHub short name
  registration.username = jwt.login;

  // Store the company and location returned from GitHub in custom user data.
  user.data = user.data || {};
  user.data.company = jwt.company;
  user.data.location = jwt.location;

  // The id_token may be available depending upon your IdP configuration.
  // - Ensure the value is defined before accessing it.
  if (id_token) {
    user.data.companyName = id_token.companyName;
  }

  // Create an event log of type 'Debug' when the lambda has Debug enabled
  console.debug('FusionAuth reconciled a User from GitHub and I helped!');
}

During development if you want to get a better idea of what your IdP is returning in the jwt object, you may print the contents of this object to the Event Log to help you write the lambda. Add the following line of code to your lambda to dump the entire object to an informational event log.

// Pretty print the jwt object to the Event Log
console.info(JSON.stringify(jwt, null, 2));

Modifying Email And Username Claims

FusionAuth will require an email or username to create a user. However, if the response from the UserInfo endpoint, or the id_token does not return an email claim you can optionally create a unique value to satisfy this requirement. This claim is email by default but may be changed with the oauth2.emailClaim as documented in the OpenID Connect Identity Provider API.

This capability is available beginning in version 1.31.0. It was also available from 1.17.3 to 1.28.0.

In this example, we will assume the jwt or id_token objects contain unique user information such as the sub claim. This unique value can be used to fabricate an email address.

function(user, registration, jwt, id_token, tokens) {
  // The user's unique Id is the 'sub' claim.
  user.email = jwt.sub + '@no-email-present.example.com';
}

Make sure you pick an email address for a domain you control to avoid malicious attacks. Modifying the username or email address may cause your lambda to be run two times. It will be run again if you modify the linking strategy claim and an existing user is found that matches.

You can’t modify an email claim if the linking strategy is username or the username claim if the linking strategy is email. Modifying the claim that is not being linked on will be ignored because doing so could cause collisions if you were to change the linking strategy later.