# Verify TOTP Quickstart

> \[!NOTE]
>
> Want to see this in action first? Check out [Twilio's Code Exchange and quick deploy a sample TOTP application](https://www.twilio.com/code-exchange/verify-totp).

> \[!NOTE]
>
> Looking for open source native libraries that generate TOTPs? Try [Kotlin One-Time Password Library](https://github.com/marcelkliemannel/kotlin-onetimepassword) for Android or [SwiftOTP](https://github.com/lachlanbell/SwiftOTP) for iOS.

Verify TOTP adds the [standards-compliant TOTP (Soft Token)](/docs/glossary/totp) channel to the Verify API, so that you can let your users use authenticator apps like [Authy](https://authy.com/), Google Authenticator, or your own custom app for authentication. It's great for businesses looking for a more secure, private, and lower-cost user authentication option compared to SMS OTP. TOTP even works when the user is offline, like on an airplane. Unlike the Authy API TOTP feature, no PII from the user is required, more user registration options beyond QR codes are supported, and you can configure more code properties.

There are three main steps to use Verify TOTP:

* Register a user by generating an [RFC-6238](https://tools.ietf.org/html/rfc6238) compliant seed.
* Verify that the user correctly added the seed (for example via QR code) to their Authenticator App
* To verify a registered user, check that the code a user provided matches the code generated by the unique seed.

This Quickstart will walk you through the entire process step-by-step, starting with setting up your Twilio account all the way through verifying a user.

In this Quickstart, you will learn how to:

1. Setup
   * Sign up for Twilio
   * Create a Verify Service
2. Register a user and TOTP seed
   * Generate a TOTP seed
   * Generate a QR code
   * Verify a successful registration
3. Verify a user
   * Create a Challenge
   * Update the Challenge

By the end of this Quickstart, you'll have a solid foundation for implementing Verify TOTP within your app and backend to verify users at login, transaction, and other sensitive actions.

## Want a technical overview first?

[Technical Overview](https://www.twilio.com/docs/verify/totp/technical-overview)

Check out the Verify TOTP Technical Overview to view its data model and sequence diagrams

## Sign up for - or sign in to - Twilio

> \[!NOTE]
>
> Already have a Twilio account? Go ahead and skip this section.

You can sign up for a free Twilio trial account [here](https://www.twilio.com/try-twilio).

* When you sign up, you'll be asked to verify your personal phone number. This helps Twilio verify your identity.
* Once you verify your number, you'll be asked to create a project. For the sake of this tutorial, you can click on the "Learn and Explore" template. Give your project a name, or just click "skip remaining steps" to continue with the default.
* Once you get through the project creation flow, you'll arrive at your project dashboard in the [Twilio Console](https://www.twilio.com/console). This is where you'll be able to access your Account SID, an authentication token, create a Verify Service and more.

## Create a Verify Service

Go to [Twilio Console > Verify > Services](https://www.twilio.com/console/verify/services) and create a new Service.

Alternatively, you can select any existing Service. However, we recommend creating a new service for testing so you don't accidentally interfere with a production environment.

## Register a user and TOTP seed

To use Verify TOTP, you first register a user by generating an [RFC-6238](https://tools.ietf.org/html/rfc6238) compliant seed. Then you verify that they've correctly added it to their Authenticator App for generating codes.

## Create a new TOTP factor

The security of TOTP relies on a shared secret between your app and your user, and this is known as the seed. Register a user by creating a TOTP factor, which generates a seed based on a set of default configs and stores it. A corresponding Entity representing your user is also auto-created if it didn't exist.

For security reasons, it is not possible to export TOTP seeds programmatically after creation and they are not returned from [the Factor API](/docs/verify/api/factor). If you do need to save seeds, we recommend performing that operation during seed creation.

When creating a TOTP factor, you can optionally pass your own seed (useful for migration scenarios) and modify the default configs. See the [Factor resource](/docs/verify/api/factor) for reference. Some default configs are also adjustable at the [Service resource](/docs/verify/api/service) level, such that all future Factors use them. Type or paste the code sample for this step.

Create a new TOTP factor

```js
// Download the helper library from https://www.twilio.com/docs/node/install
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);

async function createNewFactor() {
  const newFactor = await client.verify.v2
    .services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    .entities("ff483d1ff591898a9942916050d2ca3f")
    .newFactors.create({
      factorType: "totp",
      friendlyName: "Taylor's Account Name",
    });

  console.log(newFactor.binding);
}

createNewFactor();
```

```python
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)

new_factor = (
    client.verify.v2.services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    .entities("ff483d1ff591898a9942916050d2ca3f")
    .new_factors.create(
        friendly_name="Taylor's Account Name", factor_type="totp"
    )
)

print(new_factor.binding)
```

```csharp
// Install the C# / .NET helper library from twilio.com/docs/csharp/install

using System;
using Twilio;
using Twilio.Rest.Verify.V2.Service.Entity;
using System.Threading.Tasks;

class Program {
    public static async Task Main(string[] args) {
        // Find your Account SID and Auth Token at twilio.com/console
        // and set the environment variables. See http://twil.io/secure
        string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");

        TwilioClient.Init(accountSid, authToken);

        var newFactor = await NewFactorResource.CreateAsync(
            friendlyName: "Taylor's Account Name",
            factorType: NewFactorResource.FactorTypesEnum.Totp,
            pathServiceSid: "VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            pathIdentity: "ff483d1ff591898a9942916050d2ca3f");

        Console.WriteLine(newFactor.Binding);
    }
}
```

```java
// Install the Java helper library from twilio.com/docs/java/install

import com.twilio.Twilio;
import com.twilio.rest.verify.v2.service.entity.NewFactor;

public class Example {
    // Find your Account SID and Auth Token at twilio.com/console
    // and set the environment variables. See http://twil.io/secure
    public static final String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    public static final String AUTH_TOKEN = System.getenv("TWILIO_AUTH_TOKEN");

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
        NewFactor newFactor = NewFactor
                                  .creator("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                                      "ff483d1ff591898a9942916050d2ca3f",
                                      "Taylor's Account Name",
                                      NewFactor.FactorTypes.TOTP)
                                  .create();

        System.out.println(newFactor.getBinding());
    }
}
```

```go
// Download the helper library from https://www.twilio.com/docs/go/install
package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	verify "github.com/twilio/twilio-go/rest/verify/v2"
	"os"
)

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	// Make sure TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN exists in your environment
	client := twilio.NewRestClient()

	params := &verify.CreateNewFactorParams{}
	params.SetFriendlyName("Taylor's Account Name")
	params.SetFactorType("totp")

	resp, err := client.VerifyV2.CreateNewFactor("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
		"ff483d1ff591898a9942916050d2ca3f",
		params)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else {
		if resp.Binding != nil {
			fmt.Println(*resp.Binding)
		} else {
			fmt.Println(resp.Binding)
		}
	}
}
```

```php
<?php

// Update the path below to your autoload.php,
// see https://getcomposer.org/doc/01-basic-usage.md
require_once "/path/to/vendor/autoload.php";

use Twilio\Rest\Client;

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio = new Client($sid, $token);

$new_factor = $twilio->verify->v2
    ->services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    ->entities("ff483d1ff591898a9942916050d2ca3f")
    ->newFactors->create(
        "Taylor's Account Name", // FriendlyName
        "totp" // FactorType
    );

print $new_factor->binding;
```

```ruby
# Download the helper library from https://www.twilio.com/docs/ruby/install
require 'twilio-ruby'

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
auth_token = ENV['TWILIO_AUTH_TOKEN']
@client = Twilio::REST::Client.new(account_sid, auth_token)

new_factor = @client
             .verify
             .v2
             .services('VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
             .entities('ff483d1ff591898a9942916050d2ca3f')
             .new_factors
             .create(
               friendly_name: 'Taylor\'s Account Name',
               factor_type: 'totp'
             )

puts new_factor.binding
```

```bash
# Install the twilio-cli from https://twil.io/cli

twilio api:verify:v2:services:entities:factors:create \
   --service-sid VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
   --identity ff483d1ff591898a9942916050d2ca3f \
   --friendly-name "Taylor's Account Name" \
   --factor-type totp
```

```bash
curl -X POST "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Factors" \
--data-urlencode "FriendlyName=Taylor's Account Name" \
--data-urlencode "FactorType=totp" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "sid": "YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "service_sid": "VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "entity_sid": "YEaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "identity": "ff483d1ff591898a9942916050d2ca3f",
  "binding": {
    "secret": "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ",
    "uri": "otpauth://totp/test-issuer:John%E2%80%99s%20Account%20Name?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=test-issuer&algorithm=SHA1&digits=6&period=30"
  },
  "options": null,
  "date_created": "2015-07-30T20:00:00Z",
  "date_updated": "2015-07-30T20:00:00Z",
  "friendly_name": "Taylor's Account Name",
  "status": "unverified",
  "factor_type": "totp",
  "config": {
    "alg": "sha1",
    "skew": 1,
    "code_length": 6,
    "time_step": 30
  },
  "metadata": null,
  "url": "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Factors/YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
```

> \[!WARNING]
>
> **Do not use Personally Identifiable Information for `identity`. Use an immutable user identifier like a UUID, GUID, or SID.**\
> Verify TOTP uses **`identity`** as a unique identifier of a user. You should not use directly identifying information (aka personally identifiable information or PII) like a **person's name, home address, email or phone number, etc., as `identity`** because the systems that will process this attribute assume it is not directly identifying information.

> \[!WARNING]
>
> **Use caution when changing default configs**\
> The default configs for the TOTP code (Config.CodeLength, Config.Skew, Config.TimeStep, and Config.Alg) have been chosen for a typical TOTP use case with a 6-digit length code. Please use caution when changing these configs, as it could reduce the security of the code. For example, reducing the length of the TOTP code (Config.CodeLength) makes the code easier to guess and more vulnerable to a brute force attack. While a shorter length may be necessary for your use case, consider compensating security enhancements, such as limiting the rate at which codes can be checked, reducing Config.Skew, and reducing Config.TimeStep.
>
> The Authy app will not be able to add TOTP tokens if default configs such as Config.CodeLength or Config.TimeStep are changed. Other publicly available authenticator apps that your users might have don't support non-default configs for all mobile operating systems; see this [3rd-party analysis of authenticator apps](https://labanskoller.se/blog/2019/07/11/many-common-mobile-authenticator-apps-accept-qr-codes-for-modes-they-dont-support/) for details.
>
> Contact Twilio for further guidance.

## Create a QR code

The user needs to add the seed, and optionally metadata like Issuer and Account Name, to an authenticator app like Google Authenticator, Twilio Authy, or a custom client app that you've provided to your user. This authenticator app needs to securely store the seed and generate TOTP codes using it. A typical way for the user to add the seed is via scanning a QR code. Verify TOTP generates a standard URI (factor.binding.uri) that you can convert into a QR code for this purpose. Verify TOTP does not generate the QR code itself, but there are many free/open-source QR code generators.

For this quickstart, use [qr-code-generator.com](https://www.qr-code-generator.com/) to quickly generate a QR code by pasting the URI.

For a real implementation, you could use one of these open-source code libraries:

* **Node**: [https://github.com/soldair/node-qrcode](https://github.com/soldair/node-qrcode) or [https://www.npmjs.com/package/otplib](https://urldefense.com/v3/__https://www.google.com/url?q=https:**Awww.npmjs.com*package*otplib\&sa=D\&source=editors\&ust=1620656869799000\&usg=AOvVaw28vii7hfzXiN7ZzZ8IMrSG__;Ly8vLw!!NCc8flgU!JQDTzEzK5ABIrAdAgUQ3iYaCB3b7B0wXy6fHRQpOyAyaCPOhrqC7T8OD1mM$)
* **Go**: [https://github.com/skip2/go-qrcode](https://github.com/skip2/go-qrcode)
* **Python**: [https://pypi.org/project/PyQRCode/](https://urldefense.com/v3/__https://www.google.com/url?q=https:**Apypi.org*project*PyQRCode*\&sa=D\&source=editors\&ust=1620656869799000\&usg=AOvVaw2D-6TJi_yZjAv-dlbIG0K6__;Ly8vLy8!!NCc8flgU!JQDTzEzK5ABIrAdAgUQ3iYaCB3b7B0wXy6fHRQpOyAyaCPOhrqC7JBHCrNQ$)
* **PHP**: [https://github.com/endroid/qr-code](https://urldefense.com/v3/__https://www.google.com/url?q=https:**Agithub.com*endroid*qr-code\&sa=D\&source=editors\&ust=1620656869799000\&usg=AOvVaw3jKLchsh2v13iYYnjpNsoM__;Ly8vLw!!NCc8flgU!JQDTzEzK5ABIrAdAgUQ3iYaCB3b7B0wXy6fHRQpOyAyaCPOhrqC7CJNXgA0$)

Scan and add this QR with your favorite authenticator app to mimic what a user would do.

### Example

**Using this URI:**

```xml
otpauth://totp/Twilio:John%E2%80%99s%20Account%20Name?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=Twilio&algorithm=SHA1&digits=6&period=30
```

**Generates this QR code using [qr-code-generator.com:](https://www.qr-code-generator.com/)**

![QR code for Twilio Verify quickstart guide.](https://docs-resources.prod.twilio.com/f93b4dfe9d6650369fd20c72aebfa3e1f4989d027124cf474874e716b8dbef9f.png)

**Scanning this QR using the Twilio Authy app generates this token:**

![Twilio token 293 412 for John's account, expires in 8 seconds.](https://docs-resources.prod.twilio.com/4c2bf8de09837a99103576b17d455e678cca349b6f3f7547b09e10da91379972.jpg)

### How to share the seed without a QR code

Instead of a QR code, you can pass the seed to the user's authenticator app by displaying it for manual entry by the user (supported by most commercial authenticator apps), including it in a deep link, or sending it via another authenticated channel.

## Verify that the user has successfully registered

When the Factor is first created, it's in an "unverified" status. To verify the Factor, the user needs to demonstrate that they are able to generate a correct code based off of the seed.

Use the code generated by your authenticator app and type or paste the code sample for this step.

> \[!NOTE]
>
> Be sure to update the AuthPayload value with your latest TOTP code before sending the API request. The expiration window (Config.TimeStep) of the TOTP code defaults to 30 seconds. If the TOTP code is correct, then the Factor status will change to "verified". If it's incorrect, the Factor status will remain "unverified."

Verify a TOTP factor

```js
// Download the helper library from https://www.twilio.com/docs/node/install
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);

async function updateFactor() {
  const factor = await client.verify.v2
    .services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    .entities("ff483d1ff591898a9942916050d2ca3f")
    .factors("YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    .update({ authPayload: "293412" });

  console.log(factor.status);
}

updateFactor();
```

```python
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)

factor = (
    client.verify.v2.services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    .entities("ff483d1ff591898a9942916050d2ca3f")
    .factors("YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    .update(auth_payload="293412")
)

print(factor.status)
```

```csharp
// Install the C# / .NET helper library from twilio.com/docs/csharp/install

using System;
using Twilio;
using Twilio.Rest.Verify.V2.Service.Entity;
using System.Threading.Tasks;

class Program {
    public static async Task Main(string[] args) {
        // Find your Account SID and Auth Token at twilio.com/console
        // and set the environment variables. See http://twil.io/secure
        string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");

        TwilioClient.Init(accountSid, authToken);

        var factor = await FactorResource.UpdateAsync(
            authPayload: "293412",
            pathServiceSid: "VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            pathIdentity: "ff483d1ff591898a9942916050d2ca3f",
            pathSid: "YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");

        Console.WriteLine(factor.Status);
    }
}
```

```java
// Install the Java helper library from twilio.com/docs/java/install

import com.twilio.Twilio;
import com.twilio.rest.verify.v2.service.entity.Factor;

public class Example {
    // Find your Account SID and Auth Token at twilio.com/console
    // and set the environment variables. See http://twil.io/secure
    public static final String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    public static final String AUTH_TOKEN = System.getenv("TWILIO_AUTH_TOKEN");

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
        Factor factor = Factor
                            .updater("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                                "ff483d1ff591898a9942916050d2ca3f",
                                "YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
                            .setAuthPayload("293412")
                            .update();

        System.out.println(factor.getStatus());
    }
}
```

```go
// Download the helper library from https://www.twilio.com/docs/go/install
package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	verify "github.com/twilio/twilio-go/rest/verify/v2"
	"os"
)

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	// Make sure TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN exists in your environment
	client := twilio.NewRestClient()

	params := &verify.UpdateFactorParams{}
	params.SetAuthPayload("293412")

	resp, err := client.VerifyV2.UpdateFactor("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
		"ff483d1ff591898a9942916050d2ca3f",
		"YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
		params)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else {
		if resp.Status != nil {
			fmt.Println(resp.Status)
		} else {
			fmt.Println(resp.Status)
		}
	}
}
```

```php
<?php

// Update the path below to your autoload.php,
// see https://getcomposer.org/doc/01-basic-usage.md
require_once "/path/to/vendor/autoload.php";

use Twilio\Rest\Client;

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio = new Client($sid, $token);

$factor = $twilio->verify->v2
    ->services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    ->entities("ff483d1ff591898a9942916050d2ca3f")
    ->factors("YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    ->update(["authPayload" => "293412"]);

print $factor->status;
```

```ruby
# Download the helper library from https://www.twilio.com/docs/ruby/install
require 'twilio-ruby'

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
auth_token = ENV['TWILIO_AUTH_TOKEN']
@client = Twilio::REST::Client.new(account_sid, auth_token)

factor = @client
         .verify
         .v2
         .services('VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
         .entities('ff483d1ff591898a9942916050d2ca3f')
         .factors('YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
         .update(auth_payload: '293412')

puts factor.status
```

```bash
# Install the twilio-cli from https://twil.io/cli

twilio api:verify:v2:services:entities:factors:update \
   --service-sid VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
   --identity ff483d1ff591898a9942916050d2ca3f \
   --sid YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
   --auth-payload 293412
```

```bash
curl -X POST "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Factors/YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
--data-urlencode "AuthPayload=293412" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "sid": "YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "service_sid": "VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "entity_sid": "YEaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "identity": "ff483d1ff591898a9942916050d2ca3f",
  "date_created": "2015-07-30T20:00:00Z",
  "date_updated": "2015-07-30T20:00:00Z",
  "friendly_name": "friendly_name",
  "status": "verified",
  "factor_type": "totp",
  "config": {
    "alg": "sha1",
    "skew": 1,
    "code_length": 6,
    "time_step": 30
  },
  "metadata": null,
  "url": "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Factors/YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
```

> \[!NOTE]
>
> The Factor SID (`YFXXX..`) is included in the response when you create a Factor. If you don't have the Factor SID, you can List Factors for your user's Entity, and identify the one that is factor\_type = totp.

List Factors

```js
// Download the helper library from https://www.twilio.com/docs/node/install
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);

async function listFactor() {
  const factors = await client.verify.v2
    .services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    .entities("ff483d1ff591898a9942916050d2ca3f")
    .factors.list({ limit: 20 });

  factors.forEach((f) => console.log(f.sid));
}

listFactor();
```

```python
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)

factors = (
    client.verify.v2.services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    .entities("ff483d1ff591898a9942916050d2ca3f")
    .factors.list(limit=20)
)

for record in factors:
    print(record.sid)
```

```csharp
// Install the C# / .NET helper library from twilio.com/docs/csharp/install

using System;
using Twilio;
using Twilio.Rest.Verify.V2.Service.Entity;
using System.Threading.Tasks;

class Program {
    public static async Task Main(string[] args) {
        // Find your Account SID and Auth Token at twilio.com/console
        // and set the environment variables. See http://twil.io/secure
        string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");

        TwilioClient.Init(accountSid, authToken);

        var factors = await FactorResource.ReadAsync(
            pathServiceSid: "VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            pathIdentity: "ff483d1ff591898a9942916050d2ca3f",
            limit: 20);

        foreach (var record in factors) {
            Console.WriteLine(record.Sid);
        }
    }
}
```

```java
// Install the Java helper library from twilio.com/docs/java/install

import com.twilio.Twilio;
import com.twilio.rest.verify.v2.service.entity.Factor;
import com.twilio.base.ResourceSet;

public class Example {
    // Find your Account SID and Auth Token at twilio.com/console
    // and set the environment variables. See http://twil.io/secure
    public static final String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    public static final String AUTH_TOKEN = System.getenv("TWILIO_AUTH_TOKEN");

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
        ResourceSet<Factor> factors =
            Factor.reader("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "ff483d1ff591898a9942916050d2ca3f").limit(20).read();

        for (Factor record : factors) {
            System.out.println(record.getSid());
        }
    }
}
```

```go
// Download the helper library from https://www.twilio.com/docs/go/install
package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	verify "github.com/twilio/twilio-go/rest/verify/v2"
	"os"
)

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	// Make sure TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN exists in your environment
	client := twilio.NewRestClient()

	params := &verify.ListFactorParams{}
	params.SetLimit(20)

	resp, err := client.VerifyV2.ListFactor("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
		"ff483d1ff591898a9942916050d2ca3f",
		params)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else {
		for record := range resp {
			if resp[record].Sid != nil {
				fmt.Println(*resp[record].Sid)
			} else {
				fmt.Println(resp[record].Sid)
			}
		}
	}
}
```

```php
<?php

// Update the path below to your autoload.php,
// see https://getcomposer.org/doc/01-basic-usage.md
require_once "/path/to/vendor/autoload.php";

use Twilio\Rest\Client;

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio = new Client($sid, $token);

$factors = $twilio->verify->v2
    ->services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    ->entities("ff483d1ff591898a9942916050d2ca3f")
    ->factors->read(20);

foreach ($factors as $record) {
    print $record->sid;
}
```

```ruby
# Download the helper library from https://www.twilio.com/docs/ruby/install
require 'twilio-ruby'

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
auth_token = ENV['TWILIO_AUTH_TOKEN']
@client = Twilio::REST::Client.new(account_sid, auth_token)

factors = @client
          .verify
          .v2
          .services('VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
          .entities('ff483d1ff591898a9942916050d2ca3f')
          .factors
          .list(limit: 20)

factors.each do |record|
   puts record.sid
end
```

```bash
# Install the twilio-cli from https://twil.io/cli

twilio api:verify:v2:services:entities:factors:list \
   --service-sid VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
   --identity ff483d1ff591898a9942916050d2ca3f
```

```bash
curl -X GET "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Factors?PageSize=20" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "factors": [
    {
      "sid": "YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "service_sid": "VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "entity_sid": "YEaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "identity": "ff483d1ff591898a9942916050d2ca3f",
      "date_created": "2015-07-30T20:00:00Z",
      "date_updated": "2015-07-30T20:00:00Z",
      "friendly_name": "friendly_name",
      "status": "unverified",
      "factor_type": "totp",
      "config": {
        "alg": "sha1",
        "skew": 1,
        "code_length": 6,
        "time_step": 30
      },
      "metadata": null,
      "url": "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Factors/YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    }
  ],
  "meta": {
    "page": 0,
    "page_size": 50,
    "first_page_url": "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Factors?PageSize=50&Page=0",
    "previous_page_url": null,
    "url": "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Factors?PageSize=50&Page=0",
    "next_page_url": null,
    "key": "factors"
  }
}
```

## Verify a user

Congratulations! You've just completed the first Verify TOTP sequence: register user and TOTP seed. The second sequence is to verify (authenticate) a user with their authenticator app, whenever they need to login to your app or perform some other sensitive action. Read on for the step-by-step instructions.

## Validate a token

To verify a user, the user needs to read the latest code generated by their authenticator app and provide it to you. Then you need to create a Challenge and include the code as the `AuthPayload`. If the code is correct, then the Challenge will be created with a status of `approved`. Incorrect codes will result in a Challenge that is created with a status of `pending`, and will eventually expire. In the event of an incorrect code, you can ask the user to provide a new code and create a new Challenge to check if it's correct. Alternatively, you can [update the existing Challenge](/docs/verify/api/challenge#update-a-challenge-resource) with a new `AuthPayload` value, but this approach is probably more complicated to implement. Type or paste the code sample for this step.

Create a TOTP challenge to validate a token

```js
// Download the helper library from https://www.twilio.com/docs/node/install
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);

async function createChallenge() {
  const challenge = await client.verify.v2
    .services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    .entities("ff483d1ff591898a9942916050d2ca3f")
    .challenges.create({
      authPayload: "123456",
      factorSid: "YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    });

  console.log(challenge.status);
}

createChallenge();
```

```python
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)

challenge = (
    client.verify.v2.services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    .entities("ff483d1ff591898a9942916050d2ca3f")
    .challenges.create(
        auth_payload="123456", factor_sid="YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    )
)

print(challenge.status)
```

```csharp
// Install the C# / .NET helper library from twilio.com/docs/csharp/install

using System;
using Twilio;
using Twilio.Rest.Verify.V2.Service.Entity;
using System.Threading.Tasks;

class Program {
    public static async Task Main(string[] args) {
        // Find your Account SID and Auth Token at twilio.com/console
        // and set the environment variables. See http://twil.io/secure
        string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");

        TwilioClient.Init(accountSid, authToken);

        var challenge = await ChallengeResource.CreateAsync(
            authPayload: "123456",
            factorSid: "YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            pathServiceSid: "VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
            pathIdentity: "ff483d1ff591898a9942916050d2ca3f");

        Console.WriteLine(challenge.Status);
    }
}
```

```java
// Install the Java helper library from twilio.com/docs/java/install

import com.twilio.Twilio;
import com.twilio.rest.verify.v2.service.entity.Challenge;

public class Example {
    // Find your Account SID and Auth Token at twilio.com/console
    // and set the environment variables. See http://twil.io/secure
    public static final String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    public static final String AUTH_TOKEN = System.getenv("TWILIO_AUTH_TOKEN");

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
        Challenge challenge = Challenge
                                  .creator("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                                      "ff483d1ff591898a9942916050d2ca3f",
                                      "YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
                                  .setAuthPayload("123456")
                                  .create();

        System.out.println(challenge.getStatus());
    }
}
```

```go
// Download the helper library from https://www.twilio.com/docs/go/install
package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	verify "github.com/twilio/twilio-go/rest/verify/v2"
	"os"
)

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	// Make sure TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN exists in your environment
	client := twilio.NewRestClient()

	params := &verify.CreateChallengeParams{}
	params.SetAuthPayload("123456")
	params.SetFactorSid("YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")

	resp, err := client.VerifyV2.CreateChallenge("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
		"ff483d1ff591898a9942916050d2ca3f",
		params)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else {
		if resp.Status != nil {
			fmt.Println(resp.Status)
		} else {
			fmt.Println(resp.Status)
		}
	}
}
```

```php
<?php

// Update the path below to your autoload.php,
// see https://getcomposer.org/doc/01-basic-usage.md
require_once "/path/to/vendor/autoload.php";

use Twilio\Rest\Client;

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio = new Client($sid, $token);

$challenge = $twilio->verify->v2
    ->services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    ->entities("ff483d1ff591898a9942916050d2ca3f")
    ->challenges->create(
        "YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // FactorSid
        ["authPayload" => "123456"]
    );

print $challenge->status;
```

```ruby
# Download the helper library from https://www.twilio.com/docs/ruby/install
require 'twilio-ruby'

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
auth_token = ENV['TWILIO_AUTH_TOKEN']
@client = Twilio::REST::Client.new(account_sid, auth_token)

challenge = @client
            .verify
            .v2
            .services('VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
            .entities('ff483d1ff591898a9942916050d2ca3f')
            .challenges
            .create(
              auth_payload: '123456',
              factor_sid: 'YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
            )

puts challenge.status
```

```bash
# Install the twilio-cli from https://twil.io/cli

twilio api:verify:v2:services:entities:challenges:create \
   --service-sid VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
   --identity ff483d1ff591898a9942916050d2ca3f \
   --auth-payload 123456 \
   --factor-sid YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
```

```bash
curl -X POST "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Challenges" \
--data-urlencode "AuthPayload=123456" \
--data-urlencode "FactorSid=YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "sid": "YC02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "service_sid": "VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "entity_sid": "YEaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "identity": "ff483d1ff591898a9942916050d2ca3f",
  "factor_sid": "YFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "date_created": "2015-07-30T20:00:00Z",
  "date_updated": "2015-07-30T20:00:00Z",
  "date_responded": "2015-07-30T20:00:00Z",
  "expiration_date": "2015-07-30T20:00:00Z",
  "status": "approved",
  "responded_reason": "none",
  "details": {
    "message": "Hi! Mr. John Doe, would you like to sign up?",
    "date": "2020-07-01T12:13:14Z",
    "fields": [
      {
        "label": "Action",
        "value": "Sign up in portal"
      }
    ]
  },
  "hidden_details": {
    "ip": "172.168.1.234"
  },
  "metadata": null,
  "factor_type": "totp",
  "url": "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Challenges/YC02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "links": {
    "notifications": "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Challenges/YC02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Notifications"
  }
}
```

### Congratulations

## Where to next?

Now that you've verified your first user, we'd love your feedback on your experience and whether you plan to use Verify TOTP in production. We'd be happy to discuss your plans and offer suggestions. In addition, explore adding [Verify's other verification channels](/docs/verify) beyond TOTP.

**Let's build something amazing.**
