How to Set up Telesign for SMS in Appwrite

Idris Olubisi💡 - Sep 12 '23 - - Dev Community

Improving user engagement and interaction in web applications is crucial, and seamless communication is key. In today's interconnected digital world, SMS is still a powerful way to reach users quickly and efficiently. Incorporating this strong communication tool into a web application powered by Appwrite is easy.

In this article, we will discover the process of authenticating users through their phone numbers with the help of Appwrite's phone authentication APIs and Telesign. Find the project repository here.

Technology Overview

Telesign is an identity and customer engagement solution that provides sets of APIs for registering and verifying users using SMS, Voice, and phone number intelligence.

Prerequisites

To fully grasp the concepts presented in this tutorial, the following are required:

  • Basic understanding of JavaScript and React
  • Docker installed
  • Telesign account

Getting started

To create a Next.js starter project, we should first navigate to the desired directory and run the command below in our terminal.

    npx create-next-app@latest setup-telesign-for-sms-in-appwrite && cd setup-telesign-for-sms-in-appwrite
Enter fullscreen mode Exit fullscreen mode

After running the command, we will be prompted to answer sets of questions. We can do so as shown below:

Would you like to use TypeScript? <No>
Would you like to use ESLint? <No> 
Would you like to use Tailwind CSS? <Yes>
Would you like to use `src/` directory? <Yes>
Would you like to use App Router? (recommended) <Yes>
Would you like to customize the default import alias? <Yes>
What import alias would you like configured? @/* <Press Enter>
Enter fullscreen mode Exit fullscreen mode

The command creates a Next.js project called next_telesign and navigates into the project directory.

Next, we need to add Appwrite as a dependency. To do this, run the command below:

    npm install appwrite
Enter fullscreen mode Exit fullscreen mode

Set up Telesign as an SMS provider

Let's begin by logging in to our Telesign portal and making sure to save the Customer ID and API Keys.

Copy customer ID and API key on Telesign dashboard

Lastly, we need to create and verify a test number. Any number we configure and verify here can receive SMS. To do this, we need to navigate to the **Manage test numbers** screen.

Manage test numbers

Click the **Add a Number** button, input the required details, **Submit**, and **Verify**.

Add a number

Fill in the required information and verify

Configure and create a project on Appwrite

To get started, first, we need to create an Appwrite instance in a preferred directory by running the command below:

    docker run -it --rm \
        --volume /var/run/docker.sock:/var/run/docker.sock \
        --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
        --entrypoint="install" \
        appwrite/appwrite:latest
Enter fullscreen mode Exit fullscreen mode

On creation, we should see an appwrite folder with two files.

Appwrite folder

Secondly, we need to add Telesign as an SMS provider by modifying the environment variables in the .env file as shown below:

    _APP_SMS_PROVIDER=sms://<REPLACE WITH CREDENTIAL ID>:<REPLACE WITH API KEYS>@telesign
    _APP_SMS_FROM=<REPLACE WITH THE PHONE NUMBER WE USED IN WHEN VERIFYING TELESIGN>
Enter fullscreen mode Exit fullscreen mode

We must also ensure that the API Key provided by Telesign is URL encoded because it contains non-alphanumeric characters. To do this, we can navigate to the URLEncoder online platform, paste our API key, click the Encode button, and then copy the resulting encoded format.

Edited env variable

Lastly, 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.

    docker-compose up -d
Enter fullscreen mode Exit fullscreen mode

Set up a project on Appwrite
To get started, we need to navigate to the specified hostname and port http://localhost:80, log in, click the Create project button, input next_telesign as the name, and then click **Create**.

Create project on Appwrite

Appwrite + Telesign in Next.js

Let's begin by going to our project's main directory and creating a new folder named helper. Inside this folder, create a file called utils.js and insert the code snippet provided below:

import { Client, Account } from "appwrite";

//create client
const client = new Client();
client.setEndpoint("http://localhost/v1").setProject("REPLACE WITH PROJECT ID");

//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);
};
Enter fullscreen mode Exit fullscreen mode

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.

Secondly, we need to update the page.js file inside the app directory to include states and methods required by our application.

    "use client";
import Head from "next/head";
import { useState } from "react";
import { phoneAuth, validateSMS } from "../../helper/utils";

export default function Home() {
  const [value, setValue] = useState({
    phone: "",
    otp: "",
  });
  const [user, setUser] = useState(null);
  const [isPhoneVerify, setIsPhoneVerify] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const handleChange = (e) => {
    setValue({ ...value, [e.target.name]: e.target.value });
  };

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

  const handleValidatePhone = (e) => {
    e.preventDefault();
    setIsLoading(true);
    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}`,
        );
        setIsLoading(false);
      })
      .catch((e) => {
        alert("Error validating session!", e);
        setIsLoading(false);
      });
  };

  return (
    <div className="w-screen h-screen bg-white">
      //UI AND IMPLEMENTATION GOES HERE
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

The snippet above does the following:

  • Imports the required dependencies
  • Creates state properties to manage application state
  • Creates a handleChange function to control inputs
  • Creates a handleSubmit function that uses the phoneAuth function to create a user
  • Creates a handleValidatePhone function that uses the validateSMS function to verify the created user using the secret key sent via SMS

Lastly, we need to update the UI to display forms for creating and verifying users dynamically.

//IMPORTS GOES HERE

export default function Home() {
  //STATES AND METHOD GOES HERE

  return (
    <div className="w-screen h-screen bg-white">
      <Head>
        <title>Appwrite + Telesign </title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main className="py-4 px-4 lg:py-10 lg:px-10 w-full">
        <div className="flex justify-center mb-8">
          <h1 className="text-2xl font-medium text-gray-700">
            Appwrite + Telesign
          </h1>
        </div>
        <section className="flex justify-center">
          {isPhoneVerify ? (
            <div className="px-4 py-2 border rounded-lg w-full lg:w-2/4">
              <div className="border-b h-8 mb-4">
                <h3 className="text-gray-700">Verify phone number</h3>
              </div>
              <form onSubmit={handleValidatePhone}>
                <fieldset>
                  <label className="text-sm text-gray-400 mb-4 block">
                    OTP
                  </label>
                  <input
                    name="otp"
                    className="border w-full rounded-sm mb-6 p-2"
                    required
                    value={value.otp}
                    onChange={handleChange}
                    type="tel"
                  />
                </fieldset>
                <button
                  className="text-sm text-white px-8 py-2 rounded-sm bg-blue-600 hover:bg-blue-700"
                  disabled={isLoading}
                >
                  Validate OTP
                </button>
              </form>
            </div>
          ) : (
            <div className="px-4 py-2 border rounded-lg w-full lg:w-2/4">
              <div className="border-b h-8 mb-4">
                <h3 className="text-gray-700">
                  Authenticate with your phone number
                </h3>
              </div>
              <form onSubmit={handleSubmit}>
                <fieldset>
                  <label className="text-sm text-gray-400 mb-4 block">
                    Phone number
                  </label>
                  <input
                    name="phone"
                    className="border w-full rounded-sm mb-6 p-2"
                    required
                    value={value.phone}
                    onChange={handleChange}
                    type="tel"
                  />
                </fieldset>
                <button
                  className="text-sm text-white px-8 py-2 rounded-sm bg-blue-600 hover:bg-blue-700"
                  disabled={isLoading}
                >
                  Submit
                </button>
              </form>
            </div>
          )}
        </section>
      </main>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Now that we have completed that task, we may begin running a development server using the following command:

    npm run dev
Enter fullscreen mode Exit fullscreen mode

We should have something similar to what is shown below.

How to set up Telesign for SMS in Appwrite

Conclusion

This post discussed how to set up phone authentication in Next.js using Appwrite and Telesign. With Appwrite, developers can save application development time by leveraging intuitive authentication APIs without the associated technical overheads.

These resources might also be helpful:

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .