Controlling the frequency of MFA challenges based on device
By default a user will be required to complete an MFA challenge every time they sign in.
This behavior can be fine-tuned by configuring a rule for your Auth0 login action - for example, you could let users skip MFA if you know they have previously authenticated within the last 24 hours on the same device.
Configuring a rule with a condition to allow if you know that the user's device has been previously authenticated within the last day.
To enable this rule you must send a device ID to Authsignal.
This can be achieved by adding device_id
as an authorization param in your Auth0 integration code.
If you are already tracking device ID in your own app you can pass this value - or use the Authsignal Web SDK to pass a persistent device ID which is stored in a cookie.
For example if using the auth0-spa-js library:
await loginWithRedirect({
authorizationParams: { device_id: authsignal.anonymousId },
});
Or if using the auth0-react library:
<Auth0Provider
...
authorizationParams={{
device_id: authsignal.anonymousId,
}}
>
<Component {...pageProps} />
</Auth0Provider>
Or if using the nextjs-auth0 library:
await handleLogin(req, res, {
authorizationParams: { device_id: authsignal.anonymousId },
});
Opting out for social or federated logins
You may want to let users opt out of MFA if they are using an external social login provider, for example Google or Facebook.
This can easily be achieved by checking the connection on the event
object.
const { handleAuth0ExecutePostLogin, handleAuth0ContinuePostLogin } = require("@authsignal/node");
* @param {Event} event
* @param {PostLoginAPI} api
*/
exports.onExecutePostLogin = async (event, api) => {
if (event.connection.strategy === "auth0") {
await handleAuth0ExecutePostLogin(event, api);
}
};
exports.onContinuePostLogin = handleAuth0ContinuePostLogin;
Using the Server SDK directly for more customization and control
To allow for more customization and control you can also use the Authsignal Server SDK directly from within your Auth0 custom action.
const { Authsignal, UserActionState } = require("@authsignal/node");
* @param {Event} event
* @param {PostLoginAPI} api
*/
exports.onExecutePostLogin = async (event, api) => {
if (event.transaction?.protocol === "oauth2-refresh-token") {
return;
}
const secret = event.secrets.AUTHSIGNAL_SECRET;
const userId = event.user.user_id;
const redirectUrl = `https://${event.request.hostname}/continue`;
const authsignal = new Authsignal({ secret });
const { state, url, isEnrolled } = await authsignal.track({
action: "auth0-login",
userId,
redirectUrl,
email: event.user.email,
ipAddress: event.request.ip,
userAgent: event.request.user_agent,
deviceId: event.request.query?.["device_id"],
});
if (state === UserActionState.CHALLENGE_REQUIRED || !isEnrolled) {
api.redirect.sendUserTo(url);
}
};
* @param {Event} event
* @param {PostLoginAPI} api
*/
exports.onContinuePostLogin = async (event, api) => {
const secret = event.secrets.AUTHSIGNAL_SECRET;
const userId = event.user.user_id;
const authsignal = new Authsignal({ secret });
const result = await authsignal.validateChallenge({
token: event.request.query?.["token"],
userId,
});
if (result && result.state !== "CHALLENGE_SUCCEEDED") {
api.access.deny("Access denied");
}
};
Next steps