How to build an end-to-end encrypted chat app in Next.js: Setup and Auth
Tags: appwrite, nextjs, authentication, webdev
Published: 2022-08-26 13:15:46

Text messages have evolved during the past decade, becoming a primary source of electronic communication. As this medium is increasingly chosen as a means of passing essential information, it becomes more necessary to control what information a user can access.

## What we will be building

This article is part one of a two-part series that describes how to build an end-to-end encrypted chat with Appwrite. This post discusses authenticating and managing a user's account with the Appwrite account API. 

**GitHub URL** 

https://github.com/Iheanacho-ai/chat-app-nextjs

## Prerequisites

To get the most out of this article, you’ll need the following:
- A basic understanding of CSS, JavaScript, and React.js.
- Docker Desktop installed on your computer; run the `docker -v` command to verify that we have Docker Desktop installed. If not, install it from the [Get Docker documentation](https://docs.docker.com/get-docker/).
- An Appwrite instance running on your computer. Check out [this article](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) to create a local Appwrite instance. We will use Appwrite’s powerful account service to authenticate and manage a user's account.

## Setting up our Next.js app

[Next.js](https://nextjs.org/) is an open-source React framework that enables us to build server-side rendered static web applications.

To create our Next.js app, navigate to the preferred directory and run the terminal command below: 

```bash
    npx create-next-app@latest
    # or
    yarn create next-app
```
After creating our app, change the directory to the project and start a development server with the command below.

```bash
    cd <name of our project>
    npm run dev
```
To see our app, go to [http://localhost:3000](http://localhost:3000).


## Installing Appwrite

[Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) is an open-source, end-to-end, backend server solution that allows developers to build applications faster. 

To use Appwrite in our Next.js application, install the Appwrite client-side SDK for web applications:

```bash
    npm install appwrite
```

## Creating a new Appwrite project

When creating the Appwrite instance, we specified what hostname and port our console would live in. The default value is [localhost:80](http://localhost/).

Go to [localhost:80](http://localhost/) and create a new account to see the console.

On our console, we see a **Create Project** button. Click on it to start a new project.

![Appwrite Console](https://paper-attachments.dropbox.com/s_314B50E78D2533608F0DEE9BE97FEF3C5B7916B2F8CAC55559F4DCA3A07D86F6_1648400276700_Screenshot+64.png)

The project dashboard appears once we have created the project. At the top of the page, click the **Settings bar** to access the **Project ID** and **API Endpoint**.  

![Appwrite Console](https://paper-attachments.dropbox.com/s_CDCC771EEC3DD1A7952B9ECC238A891540F2EB28ABA71BCDC666BBFF38427CC1_1658675661680_Screenshot+486.png)


Now, copy the **Project ID** and **API Endpoint**, which we need to initialize the Appwrite Web SDK.


![Appwrite Console](https://paper-attachments.dropbox.com/s_CDCC771EEC3DD1A7952B9ECC238A891540F2EB28ABA71BCDC666BBFF38427CC1_1658675510884_Screenshot+480.png)


Next, we’ll create an `init.js` file in our project's root directory to initialize the Appwrite Web SDK.

```js
    import { Client, Account } from "appwrite";
    import Router from 'next/router'; 
    
    export const client = new Client();
    export const account = new Account(client);
    
    client
        .setEndpoint('http://localhost/v1') // Your API Endpoint
        .setProject('62d9859fd5a5923edf53') // Your project ID
    ;
    
```

## Creating the signup interface

Now, we need to create a signup form for our users in our project's `pages/``index.jsx` file. 

```jsx
    import Link from 'next/link';
  
    const Home = () => {
      return (
        <div>
          <div className="signup">
            <h2 className='form-h2'>Sign up</h2>
            <form action="">
              <label htmlFor="name">Name</label>
              <input type="text" className='signup-input' name="name" id="" />
              <label htmlFor="email">Email</label>
              <input type="email" className='signup-input' name="email" id=""/>
              <label htmlFor="password">Password</label>
              <input type="password" className='signup-input' name="password" id=""/>
              <label htmlFor="password">Confirm Password</label>
              <input type="password" className='signup-input' name="confirm password" id=""/>
              <button type='button' className= "button">Sign Up</button>
              <p>Already have an account, <Link href="/signin" className='link'>Sign in</Link></p>
            </form>
          </div>
        </div>
      )
    };
    export default Home;
```

Next, we navigate to the `styles` folder at our project's root directory, this folder contains a `global.css` file.  In the `styles/global.css` file, we’ll add the styling to our signup form.


https://gist.github.com/Iheanacho-ai/982cc4762bb129965e4a03a23a110256

Here is how our signup form looks.

![Signup form](https://paper-attachments.dropbox.com/s_CDCC771EEC3DD1A7952B9ECC238A891540F2EB28ABA71BCDC666BBFF38427CC1_1658678965536_Screenshot+488.png)

## Creating the sign-in interface

If a user has already created an account with our application, then we need to create a sign-in page to allow users to sign into their account.

First, create a `signin.jsx` file in the `pages` folder. This `pages/signin.jsx` file will contain the piece of code in the code block below.

```jsx
    const Home = () => {
      return (
        <div>
          <div className="signin">
            <h2 className='form-h2'>Sign in </h2>
            <form action="">
              <label htmlFor="email">Email</label>
              <input type="email" name= "email" className='signup-input' id=""/>
              <label htmlFor="password">Password</label>
              <input type="password" className='signup-input' name="password" id=""/>
              <button type='button' className= "button">Sign in</button>
            </form>
          </div>
        </div>
      )
    };
    export default Home;
```
Next, add styling to the sign-in page.

```css
    .signup, .signin{
      width: 400px;
      display: flex;
      flex-flow: column;
      justify-content: center;
      text-align: left;
      background: #fff;
      box-shadow: 0 10px 30px rgba(0,0,0,0.1);
      border-radius: 7px;
      margin: 10% auto;
      padding: 30px;
    }
```
Go to http://localhost:3000/signin to see our sign-in page.


![Appwrite Signin Page](https://paper-attachments.dropbox.com/s_CDCC771EEC3DD1A7952B9ECC238A891540F2EB28ABA71BCDC666BBFF38427CC1_1658678945104_Screenshot+487.png)

## Authenticating users 

In this section of the article, we’ll discuss using the form to create, authenticate, and sign in users.

**Signing up users**
In the `pages/index.jsx` file, import the `useState` React hook for handling states in our application.

```jsx
    import { useState } from 'react';
    import Link from 'next/link';
```
Next, create state variables to store the form values in the `pages/index.jsx` file.

```jsx
    const [name, setName] = useState()
    const [email, setEmail] = useState();
    const [password, setPassword] = useState();
    const [confirmPassword, setConfirmPassword] = useState();
```
The state variables do the following:
- The `name` variable stores the name of the user creating an account on our application
- The email variable stores the email of the user
- The `password` and `confirmPassword` variables store the password to the user’s account

Next, we’ll write a `signupWithEmailandPassword` function to create an account for a new user.

```jsx
    const signupWithEmailandPassword = async () => {
      if (password.length >= 8) {
        if (password === confirmPassword) {
          try {
            await account.create('unique()', email, password, name)
          }catch (error) {
            console.log(error)
          }
        }else {
          alert("password do not match")
        }
      } else {
         alert('Password length should be up to 8 characters')
      }
    }
```
The `signupWithEmailandPassword` function does the following:
- Checks whether the user’s password is equal to or exceeds eight characters
- Checks whether `password` and `confirmPassword` are the same
- Creates a new user account with the user’s email, password, and name
- Logs any error encountered to the console

Next, pass the state variables as values to the input fields and the `signupWithEmailandPassword` function to the `onClick` event listener on our **Sign up** button.

```jsx
    <form action="">
        <label htmlFor="name">Name</label>
        <input type="text" className='signup-input' name="name" value={name} onChange={(e) => setName(e.target.value)} id="" />
       <label htmlFor="email">Email</label>
        <input type="email" className='signup-input' name="email" value={email} onChange={(e) => setEmail(e.target.value)} id=""/>
        <label htmlFor="password">Password</label>
       <input type="password" className='signup-input' name="password" value={password} onChange={(e) => setPassword(e.target.value)} id=""/>
        <label htmlFor="password">Confirm Password</label>
        <input type="password" className='signup-input' name="confirm password" value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} id=""/>
        <button type='button' className= "button" onClick={signupWithEmailandPassword}>Sign Up</button>
       <p>Already have an account, <Link href="/signin" className='link'>Sign in</Link></p>
    </form>
```

Here is how our `index.jsx` file looks.


https://gist.github.com/Iheanacho-ai/72acee318020e43f85de09d17c5d73a9

Fill out the form to create an account with the application.

![Appwrite Signup from](https://paper-attachments.dropbox.com/s_CDCC771EEC3DD1A7952B9ECC238A891540F2EB28ABA71BCDC666BBFF38427CC1_1658679296753_Screenshot+489.png)

To see a list of users that have created accounts with our application, we go to the **Users** tab on the Appwrite Dashboard.

![Appwrite Signup form](https://paper-attachments.dropbox.com/s_CDCC771EEC3DD1A7952B9ECC238A891540F2EB28ABA71BCDC666BBFF38427CC1_1658679366442_Screenshot+490.png)


**Signing in users**
A user needs to sign in to create an account session. This account session allows users to interact with our application.

To sign users in, we’ll create a `signinWithEmailandPassword` function in the `init.js` file.

```jsx
    import { Client, Account } from "appwrite";
    import Router from 'next/router'; 
    export const client = new Client();
    export const account = new Account(client);
    
    client
        .setEndpoint('http://localhost/v1') // Your API Endpoint
        .setProject('62d9859fd5a5923edf53') // Your project ID
    ;
    
    export const signinWithEmailandPassword = async (email, password) => {
        try {
            await account.createEmailSession(email, password)
            Router.push("/chat")
        } catch (error) {
            console.log(error)
        }
    }
```

The `signinWithEmailandPassword` function above does the following:

- Creates a user session with the Appwrite `createEmailSession` function. This function receives email and password parameters.
- Navigates to the chat route after a user signs in.
- Logs any error encountered in the console.

Immediately after creating an account, we want a user to sign into our application. To do this, import the `signinWithEmailandPassword` function in the `pages/``index.jsx` file.

```js
    import { account, signinWithEmailandPassword } from '../init';
```
Next, we’ll call the `signinWithEmailandPassword` function in the `signupWithEmailandPassword` function.

```jsx
    const signupWithEmailandPassword = async () => {
       if (password.length >= 8) {
        if (password === confirmPassword) {
          try {
            await account.create('unique()', email, password, name)
             alert("account created successfully")
            // signes in the user
            signinWithEmailandPassword(email, password)    
           } catch (error) {
            console.log(error)
          }
         } else {
         alert("password do not match")
        }
      } else {
         alert('Password length should be up to 8 characters')
      }
    }
```

We then import the `signinWithEmailandPassword` function in our `pages/signin.jsx` file.

```jsx
    import { useState } from 'react';
    import { signinWithEmailandPassword } from '../init';
```
Next, we’ll create state variables to store our input field values `email` and `password`.

```jsx
    const [email, setEmail] = useState();
    const [password, setPassword] = useState();
```
After creating the state variables, create a `handleSignin` function that calls the `signinWithEmailandPassword` function.

```jsx
    const handleSignin = () => {
      signinWithEmailandPassword(email, password)
    }
```
We then pass the state variables as values to the input fields and the `handleSignin` function to the `onClick` event listener on our **Sign in** button.

```jsx
    <div>
      <div className="signin">
        <form action="">
          <label htmlFor="email">Email</label>
          <input type="email" className='signup-input' name="email" value={email} onChange={(e) => setEmail(e.target.value)} id=""/>
          <label htmlFor="password">Password</label>
          <input type="password" className='signup-input' name="" value={password} onChange={(e) => setPassword(e.target.value)} id=""/>
            <button type='button' className= "button" onClick={handleSignin}>Sign in</button>
        </form>
      </div>
    </div>
```
Here is how our `pages/signin.jsx` file should look at this point.

```jsx
    import { useState } from 'react';
    import { signinWithEmailandPassword } from '../init';
    
    const Home = () => {
      const [email, setEmail] = useState();
      const [password, setPassword] = useState();
      const handleSignin = () => {
        signinWithEmailandPassword(email, password)
      }
      return (
        <div>
          <div className="signin">
            <form action="">
              <label htmlFor="email">Email</label>
              <input type="email" className='signup-input' name="email" value={email} onChange={(e) => setEmail(e.target.value)} id=""/>
              <label htmlFor="password">Password</label>
              <input type="password" className='signup-input' name="" value={password} onChange={(e) => setPassword(e.target.value)} id=""/>
              <button type='button' className= "button" onClick={handleSignin}>Sign in</button>
            </form>
          </div>
        </div>
      )
    };
    
    export default Home;
```

![Appwrite Signin Form](https://paper-attachments.dropbox.com/s_CDCC771EEC3DD1A7952B9ECC238A891540F2EB28ABA71BCDC666BBFF38427CC1_1658679883003_Screenshot+491.png)

## Creating the chat interface

Let’s create a `chat.jsx` file in the `pages` folder. This file will contain the piece of code below.

```jsx
    const Chat = () => {
      return (
        <div className='chat'>
          <div className='user-chat'>
            <div className="user-chat-header">USER</div>
            <div className='messages'>
            </div>
            <div className='input-area'>
              <input type="text" className='message-input'/>
              <button className='send' type='button'>send</button>
            </div>
          </div>
        </div>
      ) 
    };
    
   export default Chat;
```

In the `global.css` file, we'll add styling to our chat interface.


https://gist.github.com/Iheanacho-ai/93956e8a24effe332efe44e4d15a8347

Here is how our chat app user interface looks.

![Chat App interface](https://paper-attachments.dropbox.com/s_CDCC771EEC3DD1A7952B9ECC238A891540F2EB28ABA71BCDC666BBFF38427CC1_1658680119674_Screenshot+492.png)


![Chat App](https://paper-attachments.dropbox.com/s_CDCC771EEC3DD1A7952B9ECC238A891540F2EB28ABA71BCDC666BBFF38427CC1_1658690364611_chat-app.gif)

## Conclusion
This article discussed using Appwrite’s Account service to authenticate and sign a user into an application.

## Resources
- [Create a local Appwrite instance in 3 steps](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba)
[](https://appwrite.io/docs/getting-started-for-web)- [Getting Started with Appwrite for Web](https://appwrite.io/docs/getting-started-for-web)
- [Account API](https://appwrite.io/docs/client/account?sdk=web-default#accountCreateOAuth2Session?utm_source=hackmamba&utm_medium=blog&utm_campaign=auth0_auth0-authentication-vue)