Generic Connector

Overview

Generic Connectors allow you to authenticate users against or migrate them from any user datasource accessible over HTTP or TLS.

Configuration

The Generic Connector creation page.

Form Fields

Id

An optional UUID. When this value is omitted a unique Id will be generated automatically.

Namerequired

A unique name to identify the Connector. This name is for display purposes only and it can be modified later if desired.

Authentication URLrequired

The fully qualified URL of the API endpoint. The connector will send an HTTP POST request to this URL to authenticate the user. The format returned will be identical to the Login API. See the response section for status codes accepted by FusionAuth from your connector.

Connect timeoutrequired

The connect timeout in milliseconds, used when making the POST request.

Read timeoutrequired

The read timeout in milliseconds, used when making the POST request.

Debug enabled

Enable debug to create an event log to assist you in debugging integration errors.

Security

The security settings may be used to require authentication in order to make the POST request to the authentication endpoint.

The Generic Connector security section.

Form Fields

Basic auth username

The username to be used for HTTP Basic Authentication.

Basic auth password

The password to be used for HTTP Basic Authentication.

Certificate

The SSL certificate to be used when connecting to the POST endpoint.

If you need to add a certificate for use with this connector, navigate to Settings -> Key Master and import a certificate. The certificate will then be shown as an option in this form control.

Headers

You can configure arbitrary headers to be added to the HTTP POST request when making a request to the configured authentication endpoint.

The Generic Connector headers section.

Form Fields

Name

The name of the header to add to the HTTP request when authenticating.

Value

The header value to add to the HTTP request when authenticating.

Using the Generic Connector

To use a Generic Connector:

  • Build a Generic Connector API endpoint in your application to expose your user data.
  • Configure the Connector in Settings -> Connectors, including securing the endpoint.
  • Add the Connector Policy in Tenants -> Your Tenant -> Connectors to configure to which domains the connector applies.

Request

The request to your API endpoint will be delivered as JSON:

Example Request JSON

{
  "loginId": "example@fusionauth.io",
  "password": "password",
  "applicationId": "10000000-0000-0002-0000-000000000001",
  "noJWT": false,
  "ipAddress": "192.168.1.42"
}

Your application will then look up the user and verify the correct credentials were provided. Then you can return the response.

Response

Your API should return a valid FusionAuth user object with status code 200 if the user is found and authenticated.

While you may return any of the attributes of the user object, including nested objects such as application registrations with roles, only the required ones must be present. The only other status code FusionAuth will accept from your connector is a 404.

A valid user object must be returned with a FusionAuth compatible UUID in the user.id . This is a requirement whether you are authenticating but not migrating a user or migrating a user.

When you are authenticating but not migrating a user, the user.id must be the same across subsequent logins.

If the user cannot be authenticated, then you should return a 404.

Response Codes
Code Description
200 The request was successful. The response will contain a JSON body.
404 To prevent enumeration attacks, a 404 is returned for any non 200 status code returned from your connector.

Response Body

user.activeBoolean

True if the User is active. False if the User has been deactivated. Deactivated Users will not be able to login.

user.birthDateString

The User’s birthdate formatted as YYYY-MM-DD

user.breachedPasswordLastCheckedInstantLong

The instant this user’s password was last checked to determine if it is compromised.

user.connectorIdUUIDAvailable since 1.18.0

The unique Id of the Connector associated with the System of Record being used to authenticate the user.

user.cleanSpeakIdUUID

This Id is used by FusionAuth when the User’s username is sent to CleanSpeak to be moderated (filtered and potentially sent to the approval queue). It is the content Id of the username inside CleanSpeak.

user.dataObject

An object that can hold any information about the User that should be persisted.

user.data.emailString

This field will be used as the email address if no user.email field is found.

This feature was removed in version 1.26.0 and added back in 1.27.2.

user.emailString

The User’s email address.

user.expiryLong

The expiration instant of the User’s account. An expired user is not permitted to login.

user.firstNameString

The first name of the User.

user.fullNameString

The User’s full name as a separate field that is not calculated from firstName and lastName .

user.idUUID

The User’s unique Id.

user.imageUrlString

The URL that points to an image file that is the User’s profile image.

user.insertInstantLong

The instant when the user was created.

user.lastLoginInstantLong

The instant when the User logged in last.

user.lastNameString

The User’s last name.

user.lastUpdateInstantLong

The instant when the User was last updated.

user.membershipsArray

The list of memberships for the User.

user.memberships[x].dataObject

An object that can hold any information about the User for this membership that should be persisted.

user.memberships[x].groupIdUUID

The Id of the Group of this membership.

user.memberships[x].idUUID

The unique Id of this membership.

user.memberships[x].insertInstantLong

The instant that the membership was created.

user.middleNameString

The User’s middle name.

user.mobilePhoneString

The User’s mobile phone number. This is useful if you will be sending push notifications or SMS messages to the User.

user.parentEmailStringAvailable since 1.7.0

The email address of the user’s parent or guardian. If this value was provided during a create or update operation, this value will only remain until the child is claimed by a parent.

user.passwordChangeRequiredBoolean

Indicates that the User’s password needs to be changed during their next login attempt.

user.passwordLastUpdateInstantLong

The instant that the User last changed their password.

user.preferredLanguagesArray<String>

An array of locale strings that give, in order, the User’s preferred languages. These are important for email templates and other localizable text. See Locales.

user.registrationsArray

The list of registrations for the User. This will include registrations for inactive applications.

user.registrations[x].applicationIdUUID

The Id of the Application that this registration is for.

user.registrations[x].authenticationTokenString

The Authentication Token for this registration (if one exists).

user.registrations[x].cleanSpeakIdUUID

This Id is used by FusionAuth when the User’s username for this registration is sent to CleanSpeak to be moderated (filtered and potentially sent to the approval queue). It is the content Id of the username inside CleanSpeak.

user.registrations[x].dataObject

An object that can hold any information about the User for this registration that should be persisted.

user.registrations[x].idUUID

The Id of this registration.

user.registrations[x].insertInstantLong

The instant that this registration was created.

user.registrations[x].lastLoginInstantLong

The instant that the User last logged into the Application for this registration.

user.registrations[x].preferredLanguagesArray<String>

An array of locale strings that give, in order, the User’s preferred languages for this registration. These are important for email templates and other localizable text.

user.registrations[x].rolesArray<String>

The list of roles that the User has for this registration. The string is the role’s Name not the role’s Id, e.g. admin or user-role.

user.registrations[x].timezoneString

The User’s preferred timezone for this registration. The string will be in an IANA time zone format.

user.registrations[x].tokensMap<String,StringDEPRECATED

A map that contains tokens returned from identity providers.

For example, if this user has authenticated using the Facebook Identity Provider, the Facebook access token will be available in this map, keyed by name Facebook. For an OpenID Connect Identity provider, or other generic providers, if a token is stored it will be keyed by the Identity Provider unique Id.

Removed in 1.28.0

The token returned and stored from the Identity Provider is now stored in the IdP link and is retrievable using the Identity Provider Link API.

user.registrations[x].usernameString

The username of the User for this registration only. This is for display purposes and cannot be used to login.

user.registrations[x].usernameStatusString

The current status of the username. This is used if you are moderating usernames via CleanSpeak. The possible values are:

  • ACTIVE - the username is active
  • PENDING - the username is pending approval/moderation
  • REJECTED - the username was rejected during moderation

If a username has been rejected, it is still possible to allow the User to update it and have the new one moderated again.

user.registrations[x].verifiedBoolean

This value indicates if this User’s registration has been verified.

For additional information, see these tutorials:

user.registrations[x].verifiedInstantLongAvailable since 1.48.0

The instant that this registration was verified.

user.tenantIdUUID

The Id of the Tenant that this User belongs to.

user.timezoneString

The User’s preferred timezone. This can be used as a default to display instants, and it is recommended that you allow Users to change this per-session. The string will be in an IANA time zone format.

user.twoFactor.methods[x].authenticator.algorithmString

The algorithm used by the TOTP authenticator. With the current implementation, this will always be HmacSHA1.

user.twoFactor.methods[x].authenticator.codeLengthInteger

The length of code generated by the TOTP. With the current implementation, this will always be 6.

user.twoFactor.methods[x].authenticator.timeStepInteger

The time-step size in seconds. With the current implementation, this will always be 30.

user.twoFactor.methods[x].emailString

The value of the email address for this method. Only present if user.twoFactor.methods[x].method is email.

user.twoFactor.methods[x].idString

The unique Id of the method.

user.twoFactor.methods[x].lastUsedBoolean

true if this method was used most recently.

user.twoFactor.methods[x].methodString

The type of this method. There will also be an object with the same value containing additional information about this method. The possible values are:

  • authenticator
  • email
  • sms
user.twoFactor.methods[x].mobilePhoneString

The value of the mobile phone for this method. Only present if user.twoFactor.methods[x].method is sms.

user.twoFactorDeliveryStringDEPRECATED

The User’s preferred delivery for verification codes during a two factor login request.

The possible values are:

  • None
  • TextMessage
Removed in 1.26.0
user.twoFactorEnabledBooleanDEPRECATED

Determines if the User has two factor authentication enabled for their account or not.

Removed in 1.26.0
user.usernameString

The username of the User.

user.usernameStatusString

The current status of the username. This is used if you are moderating usernames via CleanSpeak. The possible values are:

  • ACTIVE - the username is active
  • PENDING - the username is pending approval/moderation
  • REJECTED - the username was rejected during moderation

If a username has been rejected, it is still possible to allow the User to update it and have the new one moderated again.

user.verifiedBoolean

Whether or not the User’s email has been verified.

For additional information, see these tutorials:

user.verifiedInstantLongAvailable since 1.48.0

The instant that this email address was verified.

Note that this value is immutable and will only represent the first time the email was verified. If you enable re-verification on email change, this value will not change and will only represent the initial verification.

Example Response JSON

{
  "user": {
    "active": true,
    "breachedPasswordLastCheckedInstant": 1471786483322,
    "birthDate": "1976-05-30",
    "connectorId": "e3306678-a53a-4964-9040-1c96f36dda72",
    "data": {
      "displayName": "Johnny Boy",
      "favoriteColors": [
        "Red",
        "Blue"
      ]
    },
    "email": "example@fusionauth.io",
    "expiry": 1571786483322,
    "firstName": "John",
    "fullName": "John Doe",
    "id": "00000000-0000-0001-0000-000000000000",
    "imageUrl": "http://65.media.tumblr.com/tumblr_l7dbl0MHbU1qz50x3o1_500.png",
    "lastLoginInstant": 1471786483322,
    "lastName": "Doe",
    "memberships": [
      {
        "data": {
          "externalId": "cc6714c6-286c-411c-a6bc-ee413cda1dbc"
        },
        "groupId": "2cb5c83f-53ff-4d16-88bd-c5e3802111a5",
        "id": "27218714-305e-4408-bac0-23e7e1ddceb6",
        "insertInstant": 1471786482322
      }
    ],
    "middleName": "William",
    "mobilePhone": "303-555-1234",
    "passwordChangeRequired": false,
    "passwordLastUpdateInstant": 1471786483322,
    "preferredLanguages": [
      "en",
      "fr"
    ],
    "registrations": [
      {
        "applicationId": "10000000-0000-0002-0000-000000000001",
        "data": {
          "displayName": "Johnny",
          "favoriteSports": [
            "Football",
            "Basketball"
          ]
        },
        "id": "00000000-0000-0002-0000-000000000000",
        "insertInstant": 1446064706250,
        "lastLoginInstant": 1456064601291,
        "preferredLanguages": [
          "en",
          "fr"
        ],
        "roles": [
          "user",
          "community_helper"
        ],
        "timezone": "America/Chicago",
        "username": "johnny123",
        "usernameStatus": "ACTIVE",
        "verified": true,
        "verifiedInstant": 1698772159415
      }
    ],
    "timezone": "America/Denver",
    "tenantId": "f24aca2b-ce4a-4dad-951a-c9d690e71415",
    "twoFactor": {
      "methods": [
        {
          "authenticator": {
            "algorithm": "HmacSHA1",
            "codeLength": 6,
            "timeStep": 30
          },
          "id": "35VW",
          "method": "authenticator"
        },
        {
          "id": "V7SH",
          "method": "sms",
          "mobilePhone": "555-555-5555"
        },
        {
          "email": "example@fusionauth.io",
          "id": "7K2G",
          "method": "email"
        }
      ]
    },
    "usernameStatus": "ACTIVE",
    "username": "johnny123",
    "verified": true,
    "verifiedInstant": 1698772159415
  }
}

Example Successful Response JSON

{
  "user": {
    "active": true,
    "birthDate": "1976-05-30",
    "data": {
      "displayName": "Johnny Boy",
      "migrated": true,
      "favoriteColors": [
        "Red",
        "Blue"
      ]
    },
    "email": "example@fusionauth.io",
    "expiry": 1571786483322,
    "firstName": "John",
    "fullName": "John Doe",
    "id": "00000000-0000-0001-0000-000000000000",
    "imageUrl": "http://65.media.tumblr.com/tumblr_l7dbl0MHbU1qz50x3o1_500.png",
    "lastLoginInstant": 1471786483322,
    "lastName": "Doe",
    "middleName": "William",
    "mobilePhone": "303-555-1234",
    "passwordChangeRequired": false,
    "passwordLastUpdateInstant": 1471786483322,
    "preferredLanguages": [
      "en",
      "fr"
    ],
    "registrations": [
      {
        "applicationId": "10000000-0000-0002-0000-000000000001",
        "data": {
          "displayName": "Johnny",
          "favoriteSports": [
            "Football",
            "Basketball"
          ]
        },
        "id": "00000000-0000-0002-0000-000000000000",
        "insertInstant": 1446064706250,
        "lastLoginInstant": 1456064601291,
        "preferredLanguages": [
          "en",
          "fr"
        ],
        "roles": [
          "user",
          "community_helper"
        ],
        "username": "johnny123",
        "usernameStatus": "ACTIVE",
        "verified": true,
        "verifiedInstant": 1698772159415
      }
    ],
    "timezone": "America/Denver",
    "tenantId": "f24aca2b-ce4a-4dad-951a-c9d690e71415",
    "twoFactor": {
      "methods": [
        {
          "authenticator": {
            "algorithm": "HmacSHA1",
            "codeLength": 6,
            "timeStep": 30
          },
          "id": "35VW",
          "method": "authenticator"
        },
        {
          "id": "V7SH",
          "method": "sms",
          "mobilePhone": "555-555-5555"
        },
        {
          "email": "example@fusionauth.io",
          "id": "7K2G",
          "method": "email"
        }
      ]
    },
    "usernameStatus": "ACTIVE",
    "username": "johnny123",
    "verified": true,
    "verifiedInstant": 1698772159415
  }
}

Using the Generic Connector as the System of Record

You can use this Connector as either a source of authentication or to migrate your users. In the former case, the backing database accessed via API remains the system of record (where the canonical user data exists). In the latter, the user is moved over once they have authenticated successfully one time, and FusionAuth becomes the system of record.

As documented, there are a number of differences between these two choices. However, one difference is worth emphasizing.

When you are not migrating the user and therefore using the backing database accessed via API as the system of record, the following user attributes will reset every time the user authenticates:

  • Group memberships
  • Application registrations

If, for instance, you were to register such a user for an application using the FusionAuth API or the administrative user interface, the next time they authenticated, they would not be registered for that application.

Since FusionAuth is not the system of record, the backing database accessed via API is the authoritative data source.

The correct way to maintain these attributes is to store them in the backing database, query them when the API is called, and deliver them as part of the User JSON object.

Security

TLS v1.2

The first step in securing your Generic Connector API endpoints is to ensure that they are using TLS v1.2 or higher. You should be using a web server that is configured with a certificate from a valid certificate authority and to only receive traffic from a secure connection. We also recommend that you disable all older secure protocols including SSL, TLS 1.0 and TLS 1.1.

If you need a certificate, most cloud providers offer them or you can use LetsEncrypt to generate a certificate and ensure it is always up-to-date.

Headers

When you configure your Generic Connector API endpoint with FusionAuth, you should include a security header of some kind. There are two ways to define a security header:

  • Add a Basic Authentication username and password under the Security
  • Define an HTTP header under the Headers tab

In either case, your Generic Connector API endpoint code should validate the security header to ensure the request is coming from FusionAuth. Here’s some example code that validates an Authorization header:

Example Generic Connector API endpoint


router.route('/fusionauth-user-api').post((req, res) => {
const authorization = req.header('Authorization');
if (authorization !== 'API-KEY') {
  res.status(401).send({
    'errors': [{
      'code': '[notAuthorized]'
    }]
  });
} else {
  // process the request 
}
});

Certificates

You may provide an X.509 certificate to use with your Generic Connector API endpoint. This must be an SSL certificate previously added to the Key Master. It is used to establish a TLS connection to the Generic Connector API endpoint endpoint. Use this option if FusionAuth cannot connect to your Generic Connector API endpoint without the certificate.

Providing this certificate will build a custom SSL context for requests made for the Generic Connector API endpoint. Therefore, any other JDK keystores and certificate authority chains will be bypassed for this request.

Firewalls

In addition to using TLS and a security header, you might also want to put a firewall in front of your Generic Connector API endpoint. In most cases, this firewall will only allow traffic to your Generic Connector API endpoint that originated from your FusionAuth instance. Depending on how you are hosting your Generic Connector API endpoint, you might be able to lock down the URL for your Generic Connector API endpoint specifically. You might also leverage an API gateway or a proxy to ensure that only traffic coming from FusionAuth is routed to your Generic Connector API endpoint. The exact specifics of deploying and configuring a Firewall are outside the scope of this document, but you can consult the documentation for your proxy, API Gateway or hosting provider to determine how to manage it.

As an example, you can configure an AWS Application Load Balancer so that traffic coming from the IP address of your FusionAuth servers with a URL of https://apis.mycompany.com/fusionauth-user-api is routed through. You can then configure the Application Load Balancer so that all other traffic to that URL is rejected.

Controlling Traffic with a Proxy

Since version 1.31.0, FusionAuth can be configured to send all outbound HTTP traffic, including that from a Generic Connector API endpoint, through a proxy. This allows you examine any messages sent from FusionAuth. You can audit them, only allow connections to certain hosts, or otherwise modify them.

To configure a proxy for FusionAuth outbound traffic, use the proxy.* configuration options.

Performance Considerations

Enabled Connectors are in the critical path of the login experience and therefore should have low latency.

Set a low timeout; under one second is ideal. Increasing the timeout can result in resource starvation in FusionAuth, as more and more resources are spent on slow requests.

Here are some things to do to improve performance of your Generic Connector.

Network Connection

There are three phases of the Connector network connection, from FusionAuth connector to the API endpoint:

  • Initial connection to the API endpoint
  • First byte read from the connection
  • Response complete and returned from the API endpoint

The first two have configurable timeouts, the Connect timeout and the Read timeout fields. For Connect timeout , if the timeout expires before the connection can be established, the login fails. For Read timeout , if the timeout expires before there is data available to be read, the login fails. The default values for these timeouts are typically adequate, but you may want to tune them if there is resource contention on your server.

However, neither timeout prevents the HTTP request from taking as long as it needs to in order to respond once the API endpoint has begun to write bytes to the output stream. If a Connector is not correctly terminating the HTTP response or taking an excessive time to process the login request, then this can cause issues under load.

You can avoid issues by having your API endpoint write login data and completely close the connection as quickly as possible. You can load test your Connector using FusionAuth’s load testing framework or any other HTTP based load testing framework. Additionally, ensure the API endpoint is sized correctly and not starved of resources. You should return the appropriate status code and data as quickly as possible. Using the correct status code for each response ensures that FusionAuth handles the response appropriately.

Add Database Indices

If you are querying a database to determine whether a user can authenticate, use database tooling such as explain plan and make sure that appropriate indices have been added.

Disable Logging

Turning on the Connector’s Debug Enabled field during development is useful for troubleshooting. However, once you deploy a Connector to production, enable debugging only when troubleshooting. Debugging writes to the System -> Event Log and this causes additional load on the database.

Perform Optional Actions Out Of Band

Your connector may need to do certain other tasks after a successful login occurs. This could include calling APIs or sending messages. If these actions don’t affect the result of the authentication, have these take place after a response has been sent to FusionAuth.

One way to accomplish this is to use a queue to store relevant data, which can then be read later by a different process.

Load Test

You can load test your connector using a staging environment and the Login API. Configure the tenant to use your connector, create users in your system, and use a load testing tool to make repeated login requests of FusionAuth through your connector.

Here’s more about load testing FusionAuth.