> ## Documentation Index
> Fetch the complete documentation index at: https://docs.authsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticator app (TOTP)

> Use time-based codes from Google Authenticator and other TOTP apps.

## Portal setup

1. Navigate to [Authenticators](https://portal.authsignal.com/organisations/tenants/authenticators) in the Authsignal Portal and click on **Authenticator app (TOTP)**.

2. Activate the authenticator in the next screen.

## SDK setup

### Server SDK

Initialize the SDK using your secret key from the [API keys page](https://portal.authsignal.com/organisations/tenants/api) and the [API URL](/sdks/server/setup#regions) for your region.

<CodeGroup>
  ```ts Node.js theme={null}
  import { Authsignal } from "@authsignal/node";

  const authsignal = new Authsignal({
    apiSecretKey: "YOUR_SECRET_KEY",
    apiUrl: "YOUR_API_URL",
  });
  ```

  ```csharp C# theme={null}
  using Authsignal;

  var authsignal = new AuthsignalClient(
      apiSecretKey: "YOUR_SECRET_KEY",
      apiUrl: "YOUR_API_URL"
  );
  ```

  ```java Java theme={null}
  import com.authsignal.AuthsignalClient;

  AuthsignalClient authsignal = new AuthsignalClient(
      "YOUR_SECRET_KEY",
      "YOUR_API_URL"
  );
  ```

  ```ruby Ruby theme={null}
  require 'authsignal'

  Authsignal.setup do |config|
      config.api_secret_key = ENV["YOUR_SECRET_KEY"]
      config.api_url = "YOUR_API_URL"
  end
  ```

  ```python Python theme={null}
  from authsignal.client import AuthsignalClient

  authsignal = AuthsignalClient(
      api_secret_key="YOUR_SECRET_KEY",
      api_url="YOUR_API_URL"
  )
  ```

  ```php PHP theme={null}
  Authsignal::setApiSecretKey("YOUR_SECRET_KEY");
  Authsignal::setApiUrl("YOUR_API_URL");
  ```

  ```go Go theme={null}
  import "github.com/authsignal/authsignalgo/v2/client"

  client := NewAuthsignalClient(
      "YOUR_SECRET_KEY",
      "YOUR_API_URL",
  )
  ```
</CodeGroup>

### Client SDK

Initialize the [Web SDK](/sdks/client/web/setup) or [Mobile SDK](/sdks/client/mobile/setup) using your tenant ID from the [API keys page](https://portal.authsignal.com/organisations/tenants/api) and your [API URL](/sdks/server/setup#regions).

<CodeGroup>
  ```ts Web theme={null}
  import { Authsignal } from "@authsignal/browser";

  const authsignal = new Authsignal({
    tenantId: "YOUR_TENANT_ID",
    baseUrl: "YOUR_API_URL",
  });
  ```

  ```swift iOS theme={null}
  import Authsignal

  let authsignal = Authsignal(
      tenantID: "YOUR_TENANT_ID",
      baseURL: "YOUR_API_URL"
  )
  ```

  ```kotlin Android theme={null}
  import com.authsignal.Authsignal

  val authsignal = Authsignal(
      tenantID = "YOUR_TENANT_ID",
      baseURL = "YOUR_API_URL",
  )
  ```

  ```ts React Native theme={null}
  import { Authsignal } from "react-native-authsignal";

  const authsignal = new Authsignal({
    tenantID: "YOUR_TENANT_ID",
    baseURL: "YOUR_API_URL",
  });
  ```

  ```dart Flutter theme={null}
  import 'package:authsignal_flutter/authsignal_flutter.dart';

  final authsignal = Authsignal(
      "YOUR_TENANT_ID",
      baseURL: "YOUR_API_URL"
  );
  ```
</CodeGroup>

## Adaptive MFA

The following steps demonstrate how to implement **adaptive MFA** with authenticator app - either at sign-in or as step-up authentication when the user performs a sensitive action in your app (e.g. making a payment).

### 1. Track action

Use a [Server SDK](/sdks/server) to track an action in your backend.
This step can apply [rules](/actions-rules/rules/getting-started) to determine if a challenge is required.

<Tabs>
  <Tab title="Custom UI">
    <CodeGroup>
      ```ts Node.js theme={null}
      const request = {
        userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
        action: "signIn",
      };

      const response = await authsignal.track(request);

      const token = response.token;
      ```

      ```csharp C# theme={null}
      var request = new TrackRequest(
          UserId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          Action: "signIn"
      );

      var response = await authsignal.Track(request);

      var token = response.Token;
      ```

      ```java Java theme={null}
      TrackRequest request = new TrackRequest();
      request.userId = "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833";
      request.action = "signIn";

      TrackResponse response = authsignal.track(request).get();

      String token = response.token;
      ```

      ```ruby Ruby theme={null}
      response = Authsignal.track({
        user_id: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
        action: "signIn",
      })

      token = response[:token]
      ```

      ```python Python theme={null}
      response = authsignal.track(
          user_id="dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          action="signIn",
      )

      token = response["token"]
      ```

      ```php PHP theme={null}
      $response = Authsignal::track([
          'userId' => "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          'action' => "signIn",
      ]);

      $token = $response["token"];
      ```

      ```go Go theme={null}
      response, err := client.Track(
          TrackRequest{
              UserId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
              Action: "signIn",
          },
      )

      token := response.Token
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Pre-built UI">
    <CodeGroup>
      ```ts Node.js theme={null}
      const request = {
        userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
        action: "signIn",
        attributes: {
          redirectUrl: "https://yourapp.com/callback",
        },
      };

      const response = await authsignal.track(request);

      const url = response.url;
      ```

      ```csharp C# theme={null}
      var request = new TrackRequest(
          UserId: user.Id,
          Action: "signIn",
          Attributes: new TrackAttributes(
              RedirectUrl: "https://yourapp.com/callback"
          )
      );

      var response = await authsignal.Track(request);

      var url = response.Url;
      ```

      ```java Java theme={null}
      TrackRequest request = new TrackRequest();
      request.userId = "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833";
      request.action = "signIn";
      request.attributes = new TrackAttributes();
      request.attributes.redirectUrl = "https://yourapp.com/callback";

      TrackResponse response = authsignal.track(request).get();

      String url = response.url;
      ```

      ```ruby Ruby theme={null}
      response = Authsignal.track({
        user_id: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
        action: "signIn",
        attributes: {
          redirect_url: "https://yourapp.com/callback",
        }
      })

      url = response[:url]
      ```

      ```python Python theme={null}
      response = authsignal.track(
          user_id="dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          action="signIn",
          attributes={
              "redirectUrl": "https://yourapp.com/callback"
          }
      )

      url = response["url"]
      ```

      ```php PHP theme={null}
      $response = Authsignal::track([
          'userId' => "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          'action' => "signIn",
          'attributes' => [
              'redirectUrl' => "https://yourapp.com/callback"
          ]
      ]);

      $url = $response["url"]
      ```

      ```go Go theme={null}
      response, err := client.Track(
          TrackRequest{
              UserId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
              Action: "signIn",
              Attributes: &TrackAttributes{
                  RedirectUrl: "https://yourapp.com/callback",
              },
          },
      )

      url := response.Url
      ```
    </CodeGroup>
  </Tab>
</Tabs>

You can choose a value for the [action](/actions-rules/actions/getting-started) here which best describes what the user is doing in your app (e.g. `signIn` or `createPayment`).
Each action can have its own set of rules.
To learn more about using rules and handling different action states refer to our documentation on [actions](/actions-rules/actions/getting-started) and [rules](/actions-rules/rules/getting-started).

### 2. Present challenge

If the action state is `CHALLENGE_REQUIRED` then you can present an authenticator app challenge using the [Web SDK](/sdks/client/web/setup) or [Mobile SDK](/sdks/client/mobile/setup).

<Tabs>
  <Tab title="Custom UI">
    <CodeGroup>
      ```ts Web theme={null}
      // Set token from the track response
      authsignal.setToken("eyJhbGciOiJ...");

      // Verify the TOTP code inputted by the user
      const response = await authsignal.totp.verify({ code: "123456" });

      // Obtain a new token
      const token = response.token;
      ```

      ```swift iOS theme={null}
      // Set token from the track response
      authsignal.setToken("eyJhbGciOiJ...")

      // Verify the TOTP code inputted by the user
      let response = await authsignal.totp.verify(code: "123456")

      // Obtain a new token
      let token = response.token
      ```

      ```kotlin Android theme={null}
      // Set token from the track response
      authsignal.setToken("eyJhbGciOiJ...")

      // Verify the TOTP code inputted by the user
      val response = authsignal.totp.verify(code = "123456")

      // Obtain a new token
      val token = response.token
      ```

      ```ts React Native theme={null}
      // Set token from the track response
      await authsignal.setToken("eyJhbGciOiJ...");

      // Verify the TOTP code inputted by the user
      const response = await authsignal.totp.verify({ code: "123456" });

      // Obtain a new token
      const token = response.token;
      ```

      ```dart Flutter theme={null}
      // Set token from the track response
      await authsignal.setToken("eyJhbGciOiJ...");

      // Verify the TOTP code inputted by the user
      final response = await authsignal.totp.verify(code: "123456");

      // Obtain a new token
      final token = response.token;
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Pre-built UI">
    <CodeGroup>
      ```js Web theme={null}
      // Launch the pre-built UI with the URL from the track response
      const result = await authsignal.launch(url);

      if (result.token) {
        // Obtain a new token
        const token = result.token;
      }
      ```
    </CodeGroup>
  </Tab>
</Tabs>

### 3. Validate action

Use the new token obtained from the client SDK to validate the action on your backend.

<CodeGroup>
  ```ts Node.js theme={null}
  const response = await authsignal.validateChallenge({
    action: "signIn",
    token: "eyJhbGciOiJIUzI....",
  });

  if (response.state === "CHALLENGE_SUCCEEDED") {
    // User completed challenge successfully
  }
  ```

  ```csharp C# theme={null}
  var request = new ValidateChallengeRequest(
      Action: "signIn",
      Token: "eyJhbGciOiJIUzI...."
  );

  var response = await authsignal.ValidateChallenge(request);

  if (response.State == UserActionState.CHALLENGE_SUCCEEDED) {
      // User completed challenge successfully
  }
  ```

  ```java Java theme={null}
  ValidateChallengeRequest request = new ValidateChallengeRequest();
  request.action = "signIn";
  request.token = "eyJhbGciOiJIUzI....";

  ValidateChallengeResponse response = authsignal.validateChallenge(request).get();

  if (response.state == UserActionState.CHALLENGE_SUCCEEDED) {
     // User completed challenge successfully
  }
  ```

  ```ruby Ruby theme={null}
  response = Authsignal.validate_challenge(action: "signIn", token: "eyJhbGciOiJIUzI....")

  if response[:state] == "CHALLENGE_SUCCEEDED"
    # User completed challenge successfully
  end
  ```

  ```python Python theme={null}
  response = authsignal.validate_challenge(action="signIn", token="eyJhbGciOiJIUzI....")

  if response["state"] == "CHALLENGE_SUCCEEDED":
      # User completed challenge successfully
  ```

  ```php PHP theme={null}
  $response = Authsignal::validateChallenge(action: "signIn", token: "eyJhbGciOiJIUzI....");

  if ($response["state"] === "CHALLENGE_SUCCEEDED") {
      # User completed challenge successfully
  }
  ```

  ```go Go theme={null}
  response, err := client.ValidateChallenge(
      ValidateChallengeRequest{
          Action: "signIn",
          Token: "eyJhbGciOiJ...",
      },
  )

  if response.State == "CHALLENGE_SUCCEEDED" {
      // User completed challenge successfully
  }
  ```
</CodeGroup>

If the action state shows that the authenticator app challenge was completed successfully, you can let the user proceed with the action.

## Enrollment

The following steps demonstrate how to let users enroll an authenticator app by scanning a QR code.

### 1. Track action

Use a [Server SDK](/sdks/server) to track an action in your backend.

<Tabs>
  <Tab title="Custom UI">
    <CodeGroup>
      ```ts Node.js theme={null}
      const request = {
        userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
        action: "enroll",
      };

      const response = await authsignal.track(request);

      const token = response.token;
      ```

      ```csharp C# theme={null}
      var request = new TrackRequest(
          UserId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          Action: "enroll",
      );

      var response = await authsignal.Track(request);

      var token = response.Token;
      ```

      ```java Java theme={null}
      TrackRequest request = new TrackRequest();
      request.userId = "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833";
      request.action = "enroll";

      TrackResponse response = authsignal.track(request).get();

      String token = response.token;
      ```

      ```ruby Ruby theme={null}
      response = Authsignal.track({
        user_id: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
        action: "enroll"
      })

      token = response[:token]
      ```

      ```python Python theme={null}
      response = authsignal.track(
          user_id="dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          action="enroll"
      )

      token = response["token"]
      ```

      ```php PHP theme={null}
      $response = Authsignal::track([
          'userId' => "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          'action' => "enroll"
      ]);

      $token = $response["token"];
      ```

      ```go Go theme={null}
      response, err := client.Track(
          TrackRequest{
              UserId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
              Action: "enroll",
          },
      )


      token := response.Token
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Pre-built UI">
    <CodeGroup>
      ```ts Node.js theme={null}
      const request = {
        userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
        action: "enroll",
        attributes: {
          redirectUrl: "https://yourapp.com/callback",
        },
      };

      const response = await authsignal.track(request);

      const url = response.url;
      ```

      ```csharp C# theme={null}
      var request = new TrackRequest(
          UserId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          Action: "enroll",
          Attributes: new TrackAttributes(
              RedirectUrl: "https://yourapp.com/callback",
          )
      );

      var response = await authsignal.Track(request);

      var url = response.Url;
      ```

      ```java Java theme={null}
      TrackRequest request = new TrackRequest();
      request.userId = "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833";
      request.action = "enroll";
      request.attributes = new TrackAttributes();
      request.attributes.redirectUrl = https://yourapp.com/callback";

      TrackResponse response = authsignal.track(request).get();

      String url = response.url;
      ```

      ```ruby Ruby theme={null}
      response = Authsignal.track({
        user_id: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
        action: "enroll",
        attributes: {
          redirect_url: "https://yourapp.com/callback",
        }
      })

      url = response[:url]
      ```

      ```python Python theme={null}
      response = authsignal.track(
          user_id="dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          action="enroll",
          attributes={
              "redirectUrl": "https://yourapp.com/callback",
          }
      )

      url = response["url"]
      ```

      ```php PHP theme={null}
      $response = Authsignal::track([
          'userId' => "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
          'action' => "enroll",
          'attributes' => [
              'redirectUrl' => "https://yourapp.com/callback",
          ]
      ]);

      $url = $response["url"]
      ```

      ```go Go theme={null}
      response, err := client.Track(
          TrackRequest{
              UserId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
              Action: "enroll",
              Attributes: &TrackAttributes{
                  RedirectUrl: "https://yourapp.com/callback",
              },
          },
      )

      url := response.Url
      ```
    </CodeGroup>
  </Tab>
</Tabs>

You can choose any value for the [action](/actions-rules/actions/getting-started) here which describes the enrollment flow. This will be used to track the enrollment activity in the Authsignal Portal.

<Info>
  If the user is already enrolled with another authentication method, you will need to pass additional scopes when tracking this action - refer to our documentation on [authenticator binding](/advanced-usage/authenticator-binding) for more information.
</Info>

### 2. Present QR code

Use the [Web SDK](/sdks/client/web/setup) or [Mobile SDK](/sdks/client/mobile/setup) to present a QR code which the user can scan with their authenticator app.

<Tabs>
  <Tab title="Custom UI">
    <CodeGroup>
      ```ts Web theme={null}
      // Set token from the track response
      authsignal.setToken("eyJhbGciOiJ...");

      const response = await authsignal.totp.enroll();

      if (response.data) {
        const uri = response.data.uri; // Convert to QR code
        const secret = response.data.secret; // Can be entered manually
      }
      ```

      ```swift iOS theme={null}
      // Set token from the track response
      authsignal.setToken("eyJhbGciOiJ...")

      let response await authsignal.totp.enroll()

      if let data = response.data {
          let uri = data.uri // Convert to QR code
          let secret = data.secret // Can be entered manually
      }
      ```

      ```kotlin Android theme={null}
      // Set token from the track response
      authsignal.setToken("eyJhbGciOiJ...")

      val response = authsignal.totp.enroll()

      response.data.let {
          val uri = it.uri // Convert to QR code
          val secret = it.secret // Can be entered manually
      }
      ```

      ```ts React Native theme={null}
      // Set token from the track response
      await authsignal.setToken("eyJhbGciOiJ...");

      const response = await authsignal.totp.enroll();

      if (response.data) {
        const uri = response.data.uri; // Convert to QR code
        const secret = response.data.secret; // Can be entered manually
      }
      ```

      ```dart Flutter theme={null}
      // Set token from the track response
      await authsignal.setToken("eyJhbGciOiJ...");

      final response = await authsignal.totp.enroll();

      if (response.data != null) {
          final uri = response.data.uri; // Convert to QR code
          final secret = response.data.secret; // Can be entered manually
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Pre-built UI">
    ```js theme={null}
    // Launch the pre-built UI with the URL from the track response
    const result = await authsignal.launch(url);
    ```
  </Tab>
</Tabs>

### 3. Verify

Use the [Web SDK](/sdks/client/web/setup) or [Mobile SDK](/sdks/client/mobile/setup) to verify the code submitted by the user to complete enrollment.

<CodeGroup>
  ```ts Web theme={null}
  const response = await authsignal.totp.verify({ code: "123456" });
  ```

  ```swift iOS theme={null}
  let response = await authsignal.totp.verify(code: "123456")
  ```

  ```kotlin Android theme={null}
  val response = authsignal.totp.verify(code = "123456")
  ```

  ```ts React Native theme={null}
  const response = await authsignal.totp.verify({ code: "123456" });
  ```

  ```dart Flutter theme={null}
  final response = await authsignal.totp.verify(code: "123456");
  ```
</CodeGroup>

## Next steps

* [Pre-built UI](/implementation-options/prebuilt-ui/overview) - Rapidly deploy authenticator app challenges using our pre-built UI
* [Web SDK](/sdks/client/web/setup) - Implement authenticator app challenges while building your own UI
* [Mobile SDK](/sdks/client/mobile/setup) - Implement authenticator app challenges in native mobile apps
* [Adaptive MFA](/actions-rules/rules/adaptive-mfa) - Set up smart rules to trigger authentication based on risk
* [Passkeys](/authentication-methods/passkey/web-sdk) - Offer the most secure and user-friendly passwordless authentication
