Multi-Factor Authentication (MFA)
Overview
This guide will illustrate multi-factor authentication features in FusionAuth, including how to implement it for login and step up auth. Additional factors help ensure a system authenticates users correctly. This process is also known as MFA or Two Factor Authentication.
Types of MFA Supported
Currently there are three methods or factors of multi-factor authentication supported.
- Time-based one-time passwords (TOTP) using an application such as Google Authenticator
- SMS, including Twilio
This feature is only available in paid plans. Please visit our pricing page to learn more.
However, the Authenticator/TOTP implementation is not a premium feature.
You might be wondering, what is the difference between multi-factor authentication and two factor authentication.
A factor is anything a user has, is, or can provide which can uniquely identify the user. A password which historically has been used to identify and authenticate a user is flawed in that it is likely not globally unique, and it can be assumed that eventually it will be known by more than one person. Additional factors can be used to authenticate a user to mitigate the limitations of the traditional password.
When a system can support more than one method of authentication, it is considered to support multiple factors, or MFA. In addition to password authentication, FusionAuth supports a time based one time password, also referred to as TOTP, and an SMS or Email based one time use code. This means FusionAuth supports multiple factor authentication, or MFA.
Two-factor authentication, or 2FA more specifically refers to the practice of requiring two factors of authentication to complete a login request. In practice, this usually means requiring a password, and one additional factor of authentication.
Tenant Set Up
For each tenant, the MFA methods must be explicitly allowed in order for users within that tenant to be able to use it. This includes configuring email templates and SMS messengers. If you are using hosted login pages or the login API, enable your preferred allowed MFA methods on the tenant. If you are only using step up auth, on the other hand, you do not have to enable any tenant MFA methods.
The tenant configuration also sets the default multi-factor policy. The policy controls when MFA is required
In the image below, this tenant has all FusionAuth supported methods enabled:
Please see the Tenant configuration documentation for more information.
Application Set Up
This feature is only available in the Enterprise plan. Please visit our pricing page to learn more.
You can override some MFA configuration settings at the application level. For instance, if you have one application that is used by your administrators, you might want to require MFA. For another application used by your customers, you might want to disable MFA.
Please see the Application configuration documentation for more information.
Enabling MFA on a User
Once you’ve configured tenant settings, enable one or more MFA methods on a user. Doing this will require the user to present the additional factor of proof whenever they log in.
Since this involves sharing secrets and verifying possession of email accounts or mobile phones, you cannot enable MFA for a different user using the FusionAuth administrative user interface.
You can, however, enable MFA on your own account using the administrative user interface.
There are three options to allow users to enable multi-factor authentication on their account:
- If you have a paid edition, users may use the self service account management feature to enable MFA for their accounts. Learn more about that option here.
- You may enable MFA directly using the User API.
- You can build your own MFA user interface, allowing end users to enable MFA.
Directly Enabling MFA for a User
To directly enable MFA for a user, update their user object with one or more MFA methods.
Adding MFA methods to a user directly
API_KEY=...
curl -XPATCH -H 'Content-type: application/json' -H "Authorization: $API_KEY" \
'https://localhost.fusionauth.io/api/user/00000000-0000-0000-0000-000000000004' \
-d '{
"user": {
"twoFactor": {
"methods": [{
"method": "email",
"email": "dinesh@aol.com"
}, {
"method": "email",
"email": "dinesh@gmail.com"
}]
}
}
}'
You are using PATCH
for twoFactor
array; doing so multiple times adds to the array each time (rather than setting it to exactly what you provided in the API call). Learn more about PATCH
options.
If adding a TOTP factor, make sure you capture the secret and convey it to the user so they may enter it into their authenticator application.
There is no confirmation step when using this approach, so if an email address or phone number is incorrect, the user will never see the code sent.
You can read more about updating a user in the User API docs.
Building Your Own Interface
If building your own user interface, these are the steps to take with the API:
- If using TOTP, optionally generate a shared secret to present to the user
- If using a message based MFA method, send a code to the user
- Build a page to accept that code and enable MFA
Optionally Generate a Shared Secret
This is needed if you are using TOTP. For any other MFA method, skip this section.
Additionally, using this API is not required as you may build your own secret. The API is provided for your convenience only.
Generate a Shared Secret Sample Curl Script
API_KEY=...
curl -XGET -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/two-factor/secret'
Here’s a sample response:
Generate a Shared Secret Response JSON
{
"secret": "8MJJfCY4ERBtotvenSc3",
"secretBase32Encoded": "HBGUUSTGINMTIRKSIJ2G65DWMVXFGYZT"
}
You must present the shared secret to the user for TOTP MFA. This can be presented as a QR code or a string of digits to enter into an application such as Google Authenticator or Authy.
Unless you are using the self service account management, you’ll have to build this interface for your application.
Optionally Send a Code to the User For Message Based MFA
For email and SMS methods, send a code to the user using the Send API. If you are using TOTP, skip this section.
Send a Code Sample Curl Script
API_KEY=...
REQUEST_PAYLOAD='{...}'
curl -XPOST -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/two-factor/send' -d $REQUEST_PAYLOAD
Send a Code Sample Curl Script Request JSON
{
"email": "richard@piedpiper.com",
"method": "email",
"userId": "c075e472-a732-47d6-865a-d385a5fcb525"
}
This API call will send a unique code to the user using the method specified.
The lifetime and length of this code can be configured by navigating to Tenants -> Your Tenant -> Advanced and modifying the Two-Factor One Time Code settings.
Collect the Code
Once the code has been sent or the secret shared, accept the code from the user. Unless you are using the self service account management, you’ll have to build this page in your application.
With message based MFA methods, the user enters the code they’ve been sent. In the case of TOTP, they configure the application with the shared secret, then enter the code displayed by their application.
After your application has the code, enable MFA for this user with this API call. You must specify the method the code is associated with.
Enable MFA Sample Curl Script for the Email Method
API_KEY=...
USER_ID=...
REQUEST_PAYLOAD='{...}'
curl -XPOST -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/user/two-factor/'$USER_ID -d $REQUEST_PAYLOAD
Enable MFA for the Email Method Request JSON
{
"code": "435612",
"email": "richard@piedpiper.com",
"method": "email"
}
Verifying MFA Is Enabled
If you view the user in the administrative user interface, you can see the user has an MFA method attached to their account:
At this point, the user will be prompted to provide another factor of authentication whenever they login. This is the default screen displayed if you are using the hosted login pages:
Adding a Second Method
To enable TOTP based MFA, use a slightly different request body, which includes the code the user provides and the shared secret:
Enable MFA Sample Curl Script for TOTP Method
API_KEY=...
USER_ID=00000000-0000-0000-0000-000000000004
REQUEST_PAYLOAD='{...}'
curl -XPOST -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/user/two-factor/'$USER_ID -d $REQUEST_PAYLOAD
Enable MFA for TOTP Method Request JSON
{
"code": "435612",
"method": "authenticator",
"secret": "8MJJfCY4ERBtotvenSc3",
"twoFactorId": "a6yRXP9-FF0sqD86L_1n_zRp6iAS_aXuuhQM8OL_nIA"
}
Now that the user has two MFA methods associated with their account, the user is prompted to choose a method when logging in:
In the administrative user interface, the user has a second MFA method attached to their account:
By repeating this process, users can attach as many MFA methods of each type to their account as they wish.
Recovery Codes
When you first add an MFA method to a user, the response is a set of codes:
Recovery Codes Response JSON
{
"code": "752185",
"recoveryCodes": [
"QJD73-L6GR5",
"R7RJH-GB7H3",
"JJ5YZ-KS4C3",
"CRDHP-7L355",
"928QS-P9HMJ",
"8VLFT-Z2WMM",
"PQZX9-YV5VR",
"TK9TB-7BT6H",
"6QYPL-ZPQJV",
"VJ35W-98RW4"
]
}
These should be presented to the user to store for safekeeping. They are one time use only and may be used any time a code
parameter is required in an MFA flow. If valid, FusionAuth considers the additional factor provided and marks the recovery code used.
As a developer, you can manage them via the Recovery Code API as well.
These recovery codes are useful if a user loses their device or their email account access. By presenting a recovery code, the user may log in to their account even if they’ve lost access to their MFA method of choice.
The End User Login Experience with MFA
Once multi-factor authentication is enabled for a user, they’ll be required to provide the additional factor whenever they log in until they disable MFA.
Hosted Login Pages
If you are using hosted login pages (learn more about “hosted login pages”), there are two MFA specific templates you’ll want to modify.
- The “OAuth two-factor methods” template displays the page where a user may choose between various MFA methods.
- The “OAuth two-factor” template displays the page where a user enters an MFA code during login.
You’ll also need to modify the email or message templates if using email or SMS methods.
Here’s an example of the default template when a user has one MFA method enabled. By default, the code for the factor is sent, if applicable, and the user is prompted for the code.
Here’s an example of the default template when a user has more than one MFA method enabled. The user is then prompted to pick which method they’d like.
Learn more about themes and templates, including the variables available for each page, in the themes documentation.
Building Your Own Screens
If you are not using the hosted login pages, you’ll need to build your own pages using the Login API. In that case, you’ll want to use the following flow:
- Start the login process
- Send the code
- Complete the login
Let’s walk through each of these steps.
Log the User In
Build a page with a login form. Use the Login API docs to call the API correctly.
Log the User In Sample Curl Script
API_KEY=...
REQUEST_PAYLOAD='{...}'
curl -XPOST -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/login' -d $REQUEST_PAYLOAD
Log the User In Request JSON
{
"loginId": "example@fusionauth.io",
"password": "password",
"applicationId": "10000000-0000-0002-0000-000000000001",
"noJWT": false,
"ipAddress": "192.168.1.42"
}
If they have MFA enabled or MFA is required, your code will receive a 242
response status code. You’ll also get JSON with a list of the user’s methods:
Log the User In Response JSON When MFA Enabled
{
"methods": [
{
"authenticator": {
"algorithm": "HmacSHA1",
"codeLength": 6,
"timeStep": 30
},
"id": "2KSZ",
"method": "authenticator"
},
{
"email": "richard@fusionauth.io",
"id": "KLRT",
"method": "email"
}
],
"twoFactorId": "YkQY5Gsyo4RlfmDciBGRmvfj3RmatUqrbjoIZ19fmw4"
}
Save the twoFactorId value as you’ll need that later in the flow. Save the methods
array to present to the user when they need to choose their preferred MFA method. Implement a screen letting a user choose this.
When they have chosen a method, send a code if they are using a message based MFA method.
Optionally Send a Code
This is only required if the user chooses a message based MFA method. Calling this API invalidates any other codes previously sent to the user.
Send the Code Sample Curl Script
API_KEY=...
REQUEST_PAYLOAD='{...}'
TWO_FACTOR_ID=... # from the login response
curl -XPOST -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/two-factor/send?twoFactorId='$TWO_FACTOR_ID -d $REQUEST_PAYLOAD
Send the Code Request JSON
{
"methodId": "KLRT"
}
This sends an email because that is the MFA method corresponding to the provided methodId
.
The email address to which the code is sent may be different from the loginId
used, since the target email address for a MFA method need not be the same as the user’s login Id.
Collect the Code and Complete the Login
Build a screen to collect the code. When you have it, complete the two factor login by calling the Login API:
Complete the MFA Login Sample Curl Script
API_KEY=...
REQUEST_PAYLOAD='{...}'
curl -XPOST -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/two-factor/login' -d $REQUEST_PAYLOAD
Complete the MFA Login Request JSON
{
"applicationId": "10000000-0000-0002-0000-000000000001",
"code": "915187",
"ipAddress": "192.168.1.42",
"twoFactorId": "YkQY5Gsyo4RlfmDciBGRmvfj3RmatUqrbjoIZ19fmw4"
}
You can pass a parameter to this request indicating you want to receive a twoFactorTrustId
. That can then be provided at future logins to bypass the MFA process. Please consult the Login API documentation for more on that.
Step Up Auth
Step up authentication allows you to be extra certain that a user is who they say they are. You can use this in your application to protect sensitive actions, such as account deletion or sending money.
Step up auth is intertwined in your application in a way that normal login isn’t. Only you know what type of actions require the additional certainty of a step up. Therefore, you always need to implement a step up by calling the FusionAuth APIs.
To use this:
- Start the step up process
- Optionally send the code
- Collect the code and verify it
Here’s a diagram showing this flow for a banking application which requires step up auth before completing a transfer, but not when users view a balance.
Diagram of step up auth when user selects a message based MFA method like email.
You can also send information at the start of the step up process and receive it at the end.
Let’s walk through each of these steps.
Start the Process
Kick off the process using the start endpoint:
Start a Step Up MFA Flow Sample Curl Script
API_KEY=...
REQUEST_PAYLOAD='{...}'
curl -XPOST -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/two-factor/start' -d "$REQUEST_PAYLOAD"
Start a Step Up MFA Flow Request JSON
{
"loginId": "richard@piedpiper.com",
"applicationId": "10000000-0000-0002-0000-000000000001",
"code": "123456",
"state": {
"redirect_uri": "https://fusionauth.io"
}
}
Specify a code if you don’t want FusionAuth to generate one. You can also provide a state
object containing JSON. This is returned to you after the step up auth process completes, and can be useful to help the application return to its previous state after step up auth completes.
Start an MFA Flow Response JSON
{
"code": "123456",
"methods": [
{
"id": "BD5R",
"method": "authenticator",
"authenticator": {
"algorithm": "HmacSHA1",
"codeLength": 6,
"timeStep": 30
}
},
{
"id": "KLRT",
"method": "email",
"email": "richard@piedpiper.com",
"lastUsed": true
},
{
"id": "K8RT",
"method": "email",
"email": "dinesh@piedpiper.com"
},
{
"id": "87KW",
"method": "sms",
"mobilePhone": "+13035551212"
}
],
"twoFactorId": "DvnAUMCHLxCCAWyHXOVWPQd8ZY0a6U0e3YpYkT0MNxs"
}
Store the twoFactorId
as you’ll need that later. Present the user with the list of methods that they can choose.
When they select an MFA method, inspect it. If they choose a message based MFA method, you can send it with FusionAuth or send it via your own messaging.
If you provided your own code during the start API call, do not use FusionAuth to send that code. If you attempt to do so, FusionAuth will create a new code instead. If you provided your own code for the step up auth, send the code using your own delivery mechanism instead.
Optionally Send the Code
This is only required if the user chooses a message based MFA method and you want to send the message with FusionAuth. Unlike with the login API, you don’t have to send the code using this API with step up auth.
However, you need to get the code to the user somehow. The user doesn’t even need to have MFA enabled within FusionAuth. You could, for example, build your own integration with a chat service like Slack and send the code to the user that way. Any out of band method, even carrier pigeon, would work.
Using this request will reset the code to a different value than any provided to the start API call.
Send the Code Sample Curl Script
API_KEY=...
REQUEST_PAYLOAD='{...}'
TWO_FACTOR_ID=... # from the /api/two-factor/start response
curl -XPOST -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/two-factor/send?twoFactorId='$TWO_FACTOR_ID -d "$REQUEST_PAYLOAD"
Send the Code Request JSON
{
"methodId": "KLRT"
}
This call will send the user an email, because that is the specified method.
Complete the Step Up
Build a screen or page to collect the code. When you have it, complete the step up by calling the Login API. This will return the user object if the provided code is valid. If the code is not valid, one of the other return codes documented in the Login API will be returned.
Complete the MFA Step Up Sample Curl Script
API_KEY=...
REQUEST_PAYLOAD='{...}'
curl -XPOST -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/two-factor/login' -d "$REQUEST_PAYLOAD"
Complete the MFA Login Request JSON
{
"applicationId": "10000000-0000-0002-0000-000000000001",
"code": "915187",
"ipAddress": "192.168.1.42",
"twoFactorId": "YkQY5Gsyo4RlfmDciBGRmvfj3RmatUqrbjoIZ19fmw4"
}
If you have a valid user object, full speed ahead with the sensitive action your application was protecting!
Example Valid User Object
{
"state": {
"redirect_uri": "https://fusionauth.io"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0ODUxNDA5ODQsImlhdCI6MTQ4NTEzNzM4NCwiaXNzIjoiYWNtZS5jb20iLCJzdWIiOiIyOWFjMGMxOC0wYjRhLTQyY2YtODJmYy0wM2Q1NzAzMThhMWQiLCJhcHBsaWNhdGlvbklkIjoiNzkxMDM3MzQtOTdhYi00ZDFhLWFmMzctZTAwNmQwNWQyOTUyIiwicm9sZXMiOltdfQ.Mp0Pcwsz5VECK11Kf2ZZNF_SMKu5CgBeLN9ZOP04kZo",
"user": {
"active": true,
"email": "richard@piedpiper.com",
"expiry": 1571786483322,
"id": "00000000-0000-0001-0000-000000000000",
"lastLoginInstant": 1471786483322,
"passwordChangeRequired": false,
"passwordLastUpdateInstant": 1471786483322,
"verified": true
}
}
State For Step Up
As mentioned above, you can also store arbitrary data in the state
field. This is provided by your application when you start the step up process, and then returned after the end. This is useful in the following situations:
- Tracing a step up auth request to a given interaction, such as a transaction id.
- Reconstituting the state of the application, such as displaying a modal, after a step up display screen.
- Re-filling a multi-step form that you interrupted to display a step up challenge.
Disabling MFA on a User
Users may need to disable an MFA method. They may switch email addresses, change their phone number, or simply want to turn off MFA.
You have four options:
- If you have a paid edition, users may use the self service account management feature to disable MFA for their accounts. Learn more about that option here.
- You may remove MFA using the administrative user interface.
- You may disable MFA directly using the User API.
- You can build your own MFA user interface, allowing end users to disable MFA.
Using the Administrative User Interface
Navigate to Users -> The User and manage the user. Then go to the Multi-Factor tab. Remove any of the MFA methods by clicking the red trash can icon and confirming the deletion:
A user may also remove an MFA method by using the self service account management (if you have a paid edition) by clicking the -
link. Learn more about that here.
Directly Disabling MFA for a User
To do this, you’ll need to update the twoFactor
array.
In the below example, all methods are removed.
You could also remove just the ones with a method of email
or one particular MFA method.
Deleting MFA methods from a user directly
API_KEY=...
user=`curl -XGET -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/user/00000000-0000-0000-0000-000000000004'`
# this empties out the twoFactor array. You can use any programming language to do this, this example uses jq
user_two_factor_removed=`echo $user| jq 'del(.[].twoFactor[])' -`
curl -XPUT -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://sandbox.fusionauth.io/api/user/00000000-0000-0000-0000-000000000004' -d "$user_two_factor_removed"
The reason you need to retrieve the user and modify the data, then use PUT
to update it, is because of how PATCH
handles arrays.
Read this tracking issue for more info.
Building Your Own Interface
Building your interface allows you maximal control. To disable MFA, you need to do the following:
- Optionally send the code
- Collect the code
- Call the disable MFA API
Typically, you need to send a code to the user first. If they are using TOTP, this is optional.
Optionally Send a Code
This can be a code from one of the user’s existing MFA methods or a recovery code. To build this screen, you may need to present them with a list of available MFA methods. This is present on the user object.
If the user choose a message based MFA method, send them a code:
Send a Code For Disabling MFA Sample Curl Script
API_KEY=...
REQUEST_PAYLOAD='{...}'
curl -XPOST -H 'Content-type: application/json' -H "Authorization: $API_KEY" 'https://local.fusionauth.io/api/two-factor/send' -d $REQUEST_PAYLOAD
Send a Code For Disabling MFA Request JSON
{
"methodId": "RLRT",
"userId": "c075e472-a732-47d6-865a-d385a5fcb525"
}
This will send a code using the method specified. If a user is using a TOTP method or a recovery code, skip this.
Collect the Code
You’ll need to build a page to collect the code. This will be part of your application.
For message based MFA methods, this will be a code you sent. For TOTP MFA, this will be a code provided by an authenticator application.
Disable MFA
When you have the code, you can then call the disable API.
Send a Code For Disabling MFA Sample Curl Script
API_KEY=...
USER_ID=...
CODE=...
METHOD_ID=...
curl -XDELETE -H "Authorization: $API_KEY" 'http://localhost:9011/api/user/two-factor/'$USER_ID'?&code='$CODE'&methodId='$METHOD_ID
If this returns successfully, the MFA method has been removed from the user. If all MFA methods are removed from the user, they will no longer be prompted to provide additional factors at login.
When you use a recovery code to disable MFA, it removes all the MFA methods for a given user and invalidates all the other recovery codes.
Resending Codes
You can resend codes using message based MFA methods by calling the send API.
You may need to do this because a user requests it. For example, if a user initially requests to get a code to be sent to an email address, then realizes they really want to MFA with their mobile phone, your application may call the send endpoint twice.
Calling the send endpoint sends a new code but also invalidates all other codes associated with this MFA request.
Recovery Codes
When you first add an MFA method to a user, the response is a set of codes:
Recovery Codes Response JSON
{
"code": "752185",
"recoveryCodes": [
"QJD73-L6GR5",
"R7RJH-GB7H3",
"JJ5YZ-KS4C3",
"CRDHP-7L355",
"928QS-P9HMJ",
"8VLFT-Z2WMM",
"PQZX9-YV5VR",
"TK9TB-7BT6H",
"6QYPL-ZPQJV",
"VJ35W-98RW4"
]
}
These should be presented to the user to store for safekeeping. They are one time use only and may be used any time a code
parameter is required in an MFA flow. If valid, FusionAuth considers the additional factor provided and marks the recovery code used.
As a developer, you can manage them via the Recovery Code API as well.
These recovery codes are useful if a user loses their device or their email account access. By presenting a recovery code, the user may log in to their account even if they’ve lost access to their MFA method of choice.
Trust Tokens and Trust Challenges
Changing a password when 2FA is enabled requires a trust token. To obtain this token of trust, you can complete a two factor workflow. This is to ensure that anyone who has MFA enabled and tries to change their password also has the additional factor of authentication, which provides a higher level of assurance.
When using the hosted login pages, you don’t need to worry about this. If you are building your own MFA integration, however, read on.
For example, to change a password, you need to do the following:
- Request
/api/two-factor/start
. You get thetwoFactorId
and acode
. - Request
/api/two-factor/login
. Send in thetwoFactorId
and thecode
returned from the previous call. You’ll get atrustToken
.
This is an overview of the process. See the API docs for all parameters for these API calls.
Now you have the trustToken
required to perform a trusted action, such as changing your password while MFA is enabled. But this trust token could be stolen and used by someone else.
In order to offer a higher level of security, you can provide a trustChallenge
when you start the MFA process. Using one binds the challenge and the token. You can’t use the trustToken
without the corresponding trustChallenge
.
If you do not provide a trustChallenge
when you begin the MFA workflow, you do not need to provide anything other than the trustToken
to access a trusted endpoint such as the Change Password API.
If, on the other hand, you want to use a trustChallenge
, do the following to get the trustToken
:
- Request
/api/two-factor/start
. Send atrustChallenge
. You can provide any value, but it is best practice to make it long and random. You get thetwoFactorId
and acode
. - Request
/api/two-factor/login
. Send in thetwoFactorId
and thecode
returned from the previous call. You’ll get atrustToken
.
This is an overview of the process. See the API docs for all parameters for these API calls.
Now you have the trustToken
required to perform a trusted action, such as changing your password while MFA is enabled.
In this situation, when using the trustToken
on the Change Password API, because you provided a trustChallenge
on the /api/two-factor/start
step, the same value must be provided as well as the trustToken
to successfully use the trustToken
and complete the privileged operation.
Migration from Version 1.25 and Earlier
To migrate from the Two Factor authentication APIs provided in FusionAuth 1.25 or earlier, you’ll need to think about the following aspects:
- Your edition
- Your data
- Your code
Your Edition
If you do not have a paid FusionAuth edition, you are using the community edition. Learn more about the various editions. Due to the complexity of the new MFA implementation, SMS based MFA is no longer part of the community edition as it was before version 1.26.
Therefore if you want to use message based MFA in a version of FusionAuth after 1.25, you must purchase a paid license.
Google Authenticator and time based one-time password MFA continue to work in the community edition. TOTP MFA has been improved and you can now add multiple authenticator devices to one user account.
Your Data
If you used the Two Factor API previously, your data should be migrated transparently when you run the SQL migration.
The migrated data includes:
- Whether or not each user has MFA enabled
- Existing Twilio settings which will be converted to the new messenger configuration
- TOTP configuration
If you find your data has not migrated correctly, please file an issue and let us know. If you have an edition which includes support, please file a ticket.
Your Code
Modifying your code depends on what MFA methods you were using. To enable MFA on a user in the new system:
- Ensure the MFA method is allowed on the tenant.
- Ensure the Twilio messenger is set up correctly if you are using that.
- Instead of using the delivery field, use the method field and the corresponding method specific field such as email .
To disable MFA on a user:
- In addition to passing the userId and code fields, you also need to determine the method to disable and pass the appropriate methodId field.
When sending a code, Twilio SMS was previously your only choice. The send API is now more complicated and requires different parameters for enabling or disabling MFA on a user than sending a code for step up authentication or a login.
To migrate this functionality:
- Ensure the MFA method is allowed on the tenant.
- Ensure the Twilio messenger is set up correctly if you are using that.
- Review the API and call the send endpoint with the correct parameters.
Integrating Other MFA Methods
If you have other MFA methods that you’d like to use with FusionAuth, you have a few options:
- Check out the roadmap guidance to see if your desired method is going to be added soon. If not, the roadmap documents various ways you can request a new feature.
- If you can identify a user using their phone number and can set up a small application to process JSON requests from FusionAuth, you may use a custom Generic Messenger to send a code as a second factor. This works well with transports like SMS or any other messaging protocol.
- If you can send a code out of band, you may use step up auth to protect all the pages in your system. As soon as a user logs in, require step up auth. Users don’t have to have MFA enabled to use step up.
- If your additional factor can receive a webhook, configure your webhooks to be transactional and send one on login. The service can then perform the MFA check, perhaps doing something like fingerprint recognition. If any status other than
200
is returned, the login will fail. The downside of this approach is that the message to the end user won’t be helpful, and that MFA will be required on every login. Here is an example of a webhook stopping a login. - Use the Login API and build custom login flows, inserting your custom MFA functionality where needed.
- Set up an OpenID Connect server with the required MFA functionality. Then set up an Identity Provider that delegates to that OIDC server. Modify your theme so that this Identity Provider is the only login option.
Migrating MFA Methods From a Different System
Users with supported multi-factor methods can be migrated. By using the Users API and updating the twoFactor attributes of each user, you can migrate any of the supported MFA methods. You can use this with a bulk import or a slow migration.
twoFactor object when migrating email MFA methods
"twoFactor": {
"methods": [{
"method": "email",
"email": "dinesh@aol.com"
},
{
"method": "email",
"email": "dinesh@gmail.com"
}]
}
If your MFA method is not supported, but is message based (such as push notifications) please evaluate the Generic Messenger to see if it fits your needs. You might be able to use the SMS method with a generic messenger.
Otherwise, please open a GitHub issue detailing your use case.
Forcing MFA
There are times when you might want to force a user to provide an additional factor of authentication before they ever get access to your application. For example, you might require MFA when a user logs into an accounting application, but not when they log in to a customer support application.
In FusionAuth, this is controlled by the Login Policy setting. This can be configured at the tenant level, or, if you have the enterprise plan, at the application level. There are three values for any tenant login policy:
- Enabled
- Disabled
- Required
When the login policy is Enabled
, a two-factor challenge will be required during login when a user has configured one or more two-factor methods.
When the login policy is Disabled
, even when a user has one or more two-factor methods configured, a two-factor challenge will not be required during login.
When the login policy is Required
, a two-factor challenge will be required during login. If a user does not have configured two-factor methods, they will not be able to log in.
Alternate Methods
If login policies aren’t flexible enough for you, you can add step up authentication to your application. Each time the user accesses a sensitive part of an application, you can require a step up, which will force them to provide an additional factor.
Troubleshooting
If using the email MFA method and your emails don’t get sent, ensure you have configured your SMTP settings correctly. See the Email Troubleshooting section for more.
If using the SMS MFA method and your text messages don’t get sent, ensure that you have tested the SMS messenger configuration, enabled debugging, and reviewed the event log.
If you have enabled MFA on a user but are not prompted for MFA in the login process, ensure the MFA method associated with the user is enabled on the tenant.