Handle quick phone authentication in Next.js using Appwrite and Twilio
Tags: appwrite, authentication, twilio, nextjs
Published: 2022-10-17 08:49:53

---
title: Handle quick phone authentication in Next.js using Appwrite and Twilio
published: true
description: Learn how to authenticate a user with their phone number by leveraging Appwrite’s phone authentication APIs and Twilio. 
tags: #appwrite #authentication #twilio #nextjs
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7rh752sj685mfldsoov.png
# Use a ratio of 100:42 for best results.
---
Phone authentication has provided a more accessible and secure way to validate users' identities during onboarding or security-sensitive operations. It involves sending a user an SMS with a secret key that a system can use to validate their identity.

In this post, we will learn how to authenticate a user with their phone number by leveraging Appwrite’s phone authentication APIs and Twilio. 

## Prerequisites

To fully grasp the concepts presented in this tutorial, the following requirements apply:

- Basic understanding of JavaScript and React.
- Docker [installation](https://www.docker.com/get-started/).
- An Appwrite (*version 0.15.0*) instance; check out this [article](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) on how to set up an instance locally. Appwrite also supports one-click install on [DigitalOcean](https://marketplace.digitalocean.com/apps/appwrite) or [Gitpod](https://gitpod.io/#https://github.com/appwrite/integration-for-gitpod).
- A Twilio account; [**sign up**](https://www.twilio.com/try-twilio) for a trial account is completely free.


## Getting started

We need to create a Next.js starter project by navigating to the desired directory and running the command below in our terminal.

```bash
npx create-next-app twilio-auth && cd twilio-auth
```

The command creates a Next.js project called `twilio-auth` and navigates into the project directory.

## Installing dependencies

**Installing TailwindCSS**
[TailwindCSS](https://tailwindcss.com/) is a utility-first CSS framework packed with classes to help us style our web pages. To use it in our application, run the command below in our terminal.

```bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```

The command installs TailwindCSS and its dependencies and generates  `tailwind.config.js` and `postcss.config.js` files.

Next, we need to update `tailwind.config.js` file with the snippet below:

```js
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```
Finally, we need to add TailwindCSS directives to our application. The directives give our application access to TailwindCSS utility classes. To do this, navigate to the `styles` folder and update the `globals.css` files in it with the snippet below:

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

**Installing Appwrite**
[Appwrite](https://appwrite.io?utm_source=hackmamba&utm_medium=hackmamba-blog) is a development platform that provides a powerful API and management console for building backend servers for web and mobile applications. To install it, run the command below:

```bash
npm i appwrite@~9.0.0
```


## Set up Twilio as SMS provider

To enable phone verification with Appwrite, we need to sign into our [Twilio Console](https://console.twilio.com/) and create a virtual phone number to send SMS messages.

Click on the **Get a Twilio phone number** button:

![Get a phone number](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663777013638_Screenshot+2022-09-18+at+00.24.27.png)


Twilio will generate a **p****hone** **n****umber** for sending SMS messages, an **a****ccount SID**, and an **Auth Token**. We need to keep these parameters handy as we need them to configure and enable phone authentication on Appwrite.

![Generated details](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663777285898_Screenshot+2022-09-18+at+00.25.25.png)


**Add a** **v****erified** **p****hone** **n****umber**
Since we are using Twilio’s free trial, we need to verify the numbers we intend to send SMS to. To do this, click on the **verified phone numbers** link and click on **Add a new Caller ID** button.

![Verify](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663777952536_Screenshot+2022-09-18+at+00.26.35.png)
![Add new](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663777952573_Screenshot+2022-09-18+at+00.28.03.png)


Input the country code, phone number, and verify accordingly.

![Verify phone number](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663778040156_Screenshot+2022-09-18+at+00.28.30.png)


**Enable** **g****eographical** **p****ermission**
To avoid fraud, abuse, and high costs for voice or messaging usage, Twilio implements a geo-permissions mechanism for enabling and disabling countries that can receive voice calls and SMS messages from a Twilio account.

To enable SMS for our verified numbers, we need to search for `SMS Geographic Permissions` in the search bar, click on the **SMS Geographic Permissions** result, and then **check** the country where the verified phone number operates.

![Search](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663779185609_Screenshot+2022-09-21+at+11.36.38.png)
![Check country of operation](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663779216189_Screenshot+2022-09-21+at+17.53.12.png)



## Configure Appwrite

To get started, we need to start up the Appwrite instance on our machine and then follow the steps that follow. 

**Enabling Twilio** **s****upport in Appwrite**
To enable Twilio support with Appwrite, we need to update Appwrite’s environment variables with our Twilio credentials. To do this, first, we need to navigate to the directory created when we installed Appwrite and edit the `.env` file as shown below:


![Appwrite folder with .env file](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663789861927_Screenshot+2022-09-18+at+12.48.13.png)


```bash

//remaining env variable goes here

_APP_PHONE_PROVIDER=phone://<Account SID>:<Auth Token>@twilio
_APP_PHONE_FROM=<TWILIO GENERATED PHONE NUMBER>
```

Sample of a properly filled variables is shown below:

```bash
_APP_PHONE_PROVIDER=phone://AC6f76b2552c487994298c2f:1f6ca1acbc5667c43ea26bb@twilio
_APP_PHONE_FROM=+1234647638
```

As mentioned earlier, we can get the required credentials from Twilio console.

![Credentials](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663790209819_Screenshot+2022-09-18+at+00.25.25.png)


Secondly, we need to sync the changes we made on the `.env` file with our Appwrite server. To do this, we must run the command below inside the `appwrite` directory.

```bash
docker compose up -d --force-recreate
```
Lastly, we need to confirm that the service handling messaging on Appwrite is up and running. We can verify or start this by expanding the Appwrite project on Docker Desktop.

![Docker desktop](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663790689583_Screenshot+2022-09-21+at+14.09.53.png)


**Creating a new Appwrite project**
To create a new project, we need to navigate to the specified hostname and port `http://localhost:80`. Next, we need to log in to our account or create an account if we don’t have one. 


![Appwrite running](https://paper-attachments.dropbox.com/s_9C6F95223612512F2BFCBBAA719BAF62E5E51518F8EC1B3A16905A2D91336244_1650158621491_screencapture-localhost-auth-signup-2022-04-17-02_22_56.png)


On the console, click on the **Create Project** button, input `twilio-auth` as the name, and click **Create**.

![Create project](https://paper-attachments.dropbox.com/s_9C6F95223612512F2BFCBBAA719BAF62E5E51518F8EC1B3A16905A2D91336244_1650159125946_Screenshot+2022-04-17+at+02.28.39.png)
![Enter project name](https://paper-attachments.dropbox.com/s_BDB4B2E9DEBC947CF21789BC4224D1B5D1E6999B18844A1ABC22F2142E2E2A61_1653953612228_Screenshot+2022-05-30+at+15.00.51.png)


The project dashboard will appear on the console. Next, click on the **settings** tab and copy the **Project ID** and **API Endpoint**. 

![Copy  Project ID and API Endpoint](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663791192062_Screenshot+2022-09-18+at+01.31.27.png)




## Create phone authentication in Next.js

To get started, we’ll navigate to our project root directory and create a `helper` folder; here, create an `utils.js` file and add the snippet below:

```js
import { Client, Account } from 'appwrite';

//create client
const client = new Client();
client.setEndpoint('http://localhost/v1').setProject('PROJECT ID GOES HERE');

//create account
const account = new Account(client);

//authenticate user with phone number
export const phoneAuth = (phone_number) => {
  return account.createPhoneSession('unique()', phone_number);
};

//validate phone session
export const validateSMS = (userID, secret) => {
  return account.updatePhoneSession(userID, secret);
};
```

The snippet above does the following:

- Imports the required dependency.
- Uses the `Client` and `Account` class to set up an Appwrite instance by specifying the endpoint and corresponding project ID.
- Creates a `phoneAuth` and `validateSMS` function that uses the `createPhoneSession` and `updatePhoneSession` methods to create a user and validate the user using the code sent via SMS, respectively. 

**PS**: *The* `unique()` *string passed to the* `createPhoneSession` *method tells Appwrite to auto-generate a unique ID when creating a user.*

Finally, we need to update the `index.js` file inside the `pages` folder as shown below:

```js

import Head from 'next/head';
import { useState } from 'react';
import { phoneAuth, validateSMS } from '../helper/utils';
import styles from '../styles/Home.module.css';

export default function Home() {
  const [value, setValue] = useState({
    phone: '',
    otp: '',
  });
  const [user, setUser] = useState(null);
  const [isPhoneVerify, setIsPhoneVerify] = useState(false);

  const handleChange = (e) => {
    setValue({ ...value, [e.target.name]: e.target.value });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    phoneAuth(value.phone)
      .then((res) => {
        setUser(res.userId);
        setIsPhoneVerify(true);
      })
      .catch((e) => {
        alert('Error getting phone session!', e);
      });
  };

  const handleValidatePhone = (e) => {
    e.preventDefault();
    validateSMS(user, value.otp)
      .then((res) => {
        alert(
          `User successfully verified using for user with ID ${res.userId}, country Code ${res.countryCode}, and expires on ${res.expire}`
        );
      })
      .catch((e) => {
        alert('Error validating session!', e);
      });
  };

  return (
    <div className={styles.container}>
      <Head>
        <title>Appwrite | Twilio Auth</title>
        <meta name='description' content='Generated by appwrite twilio aauth' />
        <link rel='icon' href='/favicon.ico' />
      </Head>

      <main className='flex justify-center items-center h-screen'>
        <div className='rounded-xl w-96 p-7 shadow-xl'>
          <h1 className='text-xl font-bold mb-6 text-indigo-900 text-center'>
            Appwrite | Twilio Auth
          </h1>

          {isPhoneVerify ? (
            // Verify OTP using phone session
            <form onSubmit={handleValidatePhone}>
              <fieldset className='mb-4'>
                <label className='text-sm block mb-2'>OTP</label>
                <input
                  className='h-10 border w-full rounded border-gray-400'
                  required
                  type='number'
                  name='otp'
                  onChange={handleChange}
                />
              </fieldset>
              <button className='bg-indigo-900 w-full h-10 rounded font-semibold text-white hover:bg-indigo-700'>
                Validate OTP
              </button>
            </form>
          ) : (
            //Get Phone Session Form
            <form onSubmit={handleSubmit}>
              <fieldset className='mb-4'>
                <label className='text-sm block mb-2'>Phone Number</label>
                <input
                  className='h-10 border w-full rounded border-gray-400'
                  required
                  type='tel'
                  name='phone'
                  onChange={handleChange}
                />
              </fieldset>
              <button className='bg-indigo-900 w-full h-10 rounded font-semibold text-white hover:bg-indigo-700'>
                Submit
              </button>
            </form>
          )}
        </div>
      </main>
    </div>
  );
}
```

The snippet above does the following:

- Imports the required dependencies
- **Line****s** **7****-****12**: Create state properties to manage application state
- **Line****s** **14-16**: Create an `handleChange` function to control inputs
- **Line****s** **18-28**: Create an `handleSubmit` function that uses the `phoneAuth` function to create a user
- **Line 30****-****41**: Create an `handleValidatePhone` function that uses the `validateSMS` function to verify the created user using the secret key sent via SMS
- Modify the UI to display the forms conditionally

With that done, we can start a development server using the command below:

```bash
npm run dev
```


![](https://media.giphy.com/media/4pcCS79rGzwL2i9uMH/giphy.gif)


[https://media.giphy.com/media/4pcCS79rGzwL2i9uMH/giphy.gif](https://media.giphy.com/media/4pcCS79rGzwL2i9uMH/giphy.gif)

We can validate the created user on Appwrite and also view Message Logs on Twilio:

![Verified user on Appwrite](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663793626574_Screenshot+2022-09-21+at+14.52.00.png)
![Message log on Twilio](https://paper-attachments.dropbox.com/s_3BFCDA37590D5822C6FEFC1F3DD4F8A442FBEC418FAB7D6351861F1A86D14D5A_1663793626615_Screenshot+2022-09-21+at+17.23.40.png)



# Conclusion

This post discussed how to handle phone number authentication in Next.js using Appwrite and Twilio. With Appwrite, developers don’t have to reinvent the wheel when building authentication into their applications. They can save application development time by leveraging intuitive authentication APIs provided by Appwrite.

These resources might also be helpful:

- [Set](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) [](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba)[up Appwrite instance locally](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba)
- [Appwrite official documentation](https://appwrite.io/docs?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Twilio Geo-Permissions](https://support.twilio.com/hc/en-us/articles/223180168-What-Are-Geographic-Permissions-and-Why-do-They-Exist-)