# MFA

Extra Horizon supports multiple multifactor authentication methods. To obtain ExH access tokens you will always need the user credentials. Depending on the MFA settings of the user you will either receive the tokens or be prompted with an error requiring you to use a MFA method.

Currently Extra Horizon supports two MFA methods: **Recovery codes** and **Google Authenticator**.

## Setting up MFA

Follow the steps below to enable MFA for the first time for a user.

### Step 1 - Generate a presence token

The following endpoints require a presence token to prove the correct user is currently present. Ask for the users password and perform following request to retrieve the presence token.

```javascript
const presence = await exh.auth.confirmPresence({
  password: 'myPassword1234'
});

const presenceToken = presence.token;
```

### Step 2 - Generate recovery codes for the user

The recovery codes should be shown to the user with an indication to store them in a safe place. They are needed to reset the MFA in case they lose access to the MFA device.\\

```javascript
const recoveryMethod = await exh.auth.users.addMfaMethod(
  user.id, 
  {
    presenceToken,
    type: 'recoveryCodes',
    name: 'Recovery Codes',
  }
);
```

The recovery codes that should be displayed to the user can be found in `recoveryMethod.codes`.

### Step 3 - Generate a Google Authenticator Secret

In this step we will create a secret that the user has to use in their Google Authenticator app to add an account.

```javascript
const totpMethod = await exh.auth.users.addMfaMethod(
  user.id, 
  {
    presenceToken,
    type: 'totp',
    name: 'Google Authenticator',
  }
);

```

The secret that the user needs can be found in `totpMethod.secret`. Display the secret (for instance as a QR code) to the user and ask them to set up the account in Google Authenticator.

### Step 4 - Confirm Google Authenticator is set up correctly

Request a code given by Google Authenticator to confirm that the MFA method is setup correctly. Verify it by making the following call:

```javascript
await exh.auth.users.confirmMfaMethodVerification(
  user.id,
  totpMethod.id,
  {
    presenceToken,
    code: '<CODE COPIED FROM THE AUTHENTICATOR APP>',
  }
);
```

### Step 5 - Enable MFA

The user is now ready to start using MFA on their account. Enable MFA for the user by performing:

```javascript
await exh.auth.users.enableMfa(auth.user.id, { presenceToken });
```

## Using MFA during authentication

When a user authenticates with an email address and password and MFA is enabled, an error will be returned. You will need to catch that error and provide the One Time Password (which is a recovery code or a code given by Google Authenticator) as follows:

```javascript
try {
  await exh.auth.authenticate(tokenOrPassword);
} catch (error) {
  if (error instanceof MfaRequiredError) {
    const { mfa } = error;
    
    // Your logic to select which method the user want to use in case of multiple methods
    // As an example we simply always select the TOTP method here
    const totpMethod = mfa.methods.find(method => method.type === 'totp');

    await exh.auth.confirmMfa({
      token: mfa.token,
      methodId: totpMethod.id,
      code: "<CODE COPIED FROM THE AUTHENTICATOR APP>",
    });
    
    // The SDK is now authenticated
  }
}
```

{% hint style="warning" %}
MFA login attempts are rate limited. After each attempt the wait period increases exponentially (e.g. first attempt 1 second delay, 5th attempt 5 seconds, 10th attempt 30 seconds and so on).

When an attempt is performed during the wait period the `MFA_REATTEMPT_DELAY_EXCEPTION` is returned, stating the `remainingDelay` in the body.

The failed login count as well as the wait period will reset after a successful login.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.extrahorizon.com/extrahorizon/services/access-management/auth-service/mfa.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
