Users are required to log in to CometChat to be able to use it. Logging users in to CometChat can be as easy as calling a single method. But when it comes to security, there are a few things to consider and learn to do authentication the right way.

So in this tutorial, you'll create an example from scratch to learn the best way to integrate CometChat's authentication into your app.

CometChat authentication vs. your app authentication

It's important to know that authenticating users to CometChat is different that authenticating them to use your app. CometChat isn't a user management solution for your app. You still have to handle your app authentication yourself.

Authenticating users to CometChat is necessary if you want them to use CometChat inside your app.

So this means, you should authenticate users to your app and to CometChat.

Two ways to log users in to CometChat

To log users in to CometChat you need to use the CometChat.login() method. There are two approaches to call this method.

The first approach is to use the user's UID and the auth-only secret key. So it would look like this: CometChat.login(userUID, secret``Key``).

The second approach is to log in using only the auth token that CometChat creates for you — CometChat.login(authToken).

If you're just testing things out, it's okay to use the first approach. But in production, you should always go with the second approach as it's more secure since the secret key isn't used in it. Because as you can imagine, if the hacker could get the secret key (by reverse engineering the client code for the example), the hacker would be able to log in to any CometChat account if the username is known. But with the auth token approach, the hacker would only be able to log in to the account that the auth token was created for. Not only that, but also if the auth token’s owner has logged out, the auth token would become unusable as it would be deleted from CometChat’s servers.

In this tutorial we're going to learn how to use the auth token approach.

CometChat's authentication workflow

Before we dive into writing code, let's learn the basic workflow of authenticating users to CometChat using auth tokens.

Let's take a look at the workflow from the perspective of the frontend and the backend developers.

In the frontend:

  1. Send a request to your backend server to log the user in using his or her username/password. (This is not related to CometChat. It's for logging the user in to your app.)
  2. If the user was authenticated successfully, the server should return the logged-in user object along with the auth token for logging in to CometChat. (We haven't logged in to CometChat yet.)
  3. Use that auth token to log the user in to CometChat using CometChat.login(authToken).

In the backend:

  1. When registering a new user in your app, create a new user in CometChat using the same user id in the database. (We'll skip this step in this tutorial. We'll create the user manually from the dashboard.)
  2. In the login endpoint, you should authenticate the user to your app using his or her username/password. In this step, we're doing a regular app authentication (not for CometChat).
  3. If the user was authenticated successfully to your app, use the same user id to create a new auth token for CometChat. CometChat provides an endpoint for that.
  4. Lastly, return the logged-in user info along with the CometChat authToken.

Note that when you call CometChat.logout() this auth token is destroyed. So it's important to generate a new auth token each time the user logs in to your app.

Enough theory for now. Let’s get started with building the example app.

Creating a new user in CometChat

When building a real world app, you should create the user in CometChat programmatically. And you'd typically do it when registering the user into your app. So you'll create the CometChat user using the same id the user was registered with.

But in this tutorial, we'll skip all of this work and create it manually from the CometChat dashboard.

To do that, log in to your CometChat account, and create a new app.

Click "Explore" to open your app. Now go to "Users" tab and click "Create User".

Fill in UID with "test-user-id" and Name with "Test User". In this tutorial we're assuming that we have registered a user in our app with that id, so make sure you fill the UID with the same value.

Creating a simple Express auth server

Our auth server would be a simple Express app with a single endpoint for logging the user in.

Create a new directory and name it whatever you want, cometchat-auth-express, for example. In that directory, create package.json and add {} to it.

For this project we would need to install Express, cors, and node-fetch packages.

npm install --save express cors node-fetch

In the root directory, create app.js, and put the following into it:

const app = require('express')()
const fetch = require('node-fetch')
const cors = require('cors')
const port = 3000

const userInDB = {
  id: 'test-user-id',
  email: '[email protected]',
  password: 'password'
}

app.use(cors())

app.get('/login', async (req, res) => {
  res.send('Login page')
})

app.listen(port, () =>
  console.log(`Your server is running on port ${port}`)
)

This is a simple Express app that displays "Login page" if you go to http://localhost:3000/login.

In this example, we're assuming that we have a user stored in the database with this data:

const userInDB = {
  id: 'test-user-id',
  email: '[email protected]',
  password: 'password'
}

Note how it has the same id as the one we created from the CometChat dashboard. They should be the same so we can fetch this user's CometChat account very easily.

As you can see in app.js, we are using the cors middleware to enable browser requests from all domains. We need this because our client app will run on a different port.

To make sure this app works, run it using node app.js.

Authenticating the user

In real world apps, you should define the /login endpoint as a POST endpoint. But to keep things simple, let's keep it as a GET endpoint.

In the login endpoint, we would receive the email and the password as query params, and compare them with the values inside userInDB object. If they are the same, then we should authenticate the user to the app itself (not CometChat).

Below userInDB, let's add a new function and name it authenticate(email, password). We'll use it for authenticating the coming email and password.

function authenticate (email, password) {
  return email === userInDB.email && password === userInDB.password
    ? userInDB
    : false
}

It's just a simple comparison with what's in userInDB.

Now let's use it inside the login endpoint.

app.get('/login', async (req, res) => {
  let user = authenticate(req.query.email, req.query.password)
  if (user) {
    // The user is authenticated.
    // Now let's create an auth token for CometChat
  } else {
    res
      .status(401)
      .json({
        message: 'Your email or password is wrong!'
      })
  }
})

So the authenticate function returns the data of the authenticated user if the email and password are correct. If they are wrong, it returns false, which means we should send an error with the 401 status (UNAUTHORIZED).

Creating a new CometChat auth token

According to the CometChat docs, we can create a new auth token by sending a POST request to https://api-eu.cometchat.io/v2.0/users/``**[USER_ID]**``/auth_tokens. But for that to work, we should include the secret key and App ID in the request's header.

You can get your secret key and App ID, from the Secret Keys tab in the CometChat dashboard.

After the user is authenticated, let's create the auth token and send it along with the user object.

app.get('/login', async (req, res) => {
  let user = authenticate(req.query.email, req.query.password)
  if (user) {
    const response = await fetch(`https://api-eu.cometchat.io/v2.0/users/${user.id}/auth_tokens`, {
      method: 'post',
      headers: {
        'content-type': 'application/json',
        'accept': 'application/json',
        'apikey': 'your-api-key',
        'appid': 'your-app-id'
      }
    })
    const result = await response.json()
    res
      .status(200)
      .json({
        id: user.id,
        email: user.email,
        cometchatAuthToken: result.data.authToken
      })
  } else {
    res
      .status(401)
      .json({
        message: 'Your email or password is wrong!'
      })
  }
})

Creating the client app

The auth server is ready to be used. So let's test it with a simple client app built with Vue.

Note that you can build the client app using any other technology you want. It could be even a mobile app. Here, I am using Vue and its prototyping feature for demonstration purposes only — you can use any front-end technology you like because the core authentication logic and flow will remain the same.

Instead of creating a complete Vue project, let's use the Vue CLI's instant prototyping feature so we can run the app through a single vue file.

If you don't have Vue CLI or its global addons installed on your machine, install them using this:

npm install -g @vue/cli @vue/cli-service-global

Now you can run Vue components using vue serve YourVueComponent.vue.

In a new directory, create App.vue, and add this into it:

<template>
  <div class="app">
    <form @submit.prevent="logIn">
      <h1>Login</h1>
      <input
        v-model="email"
        type="email"
        placeholder="Email Address"
        required
      >
      <input
        v-model="password"
        type="password"
        placeholder="Password"
        required
      >
      <button type="submit">
        LOG IN
      </button>
    </form>
  </div>
</template>

<script>
export default {
  data () {
    return {
      email: '',
      password: ''
    }
  },

  methods: {
    async logIn () {}
  }
}
</script>

<style>
* {
  box-sizing: border-box;
}

html, body, .app {
  padding: 0;
  margin: 0;
  height: 100%;
  width: 100%;
}

body {
  background: hsl(268, 76%, 97%);
  font-family: Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

.app {
  display: flex;
  justify-content: center;
  align-items: center;
}

form {
  margin: 0;
  padding: 40px 30px;
  border-radius: 3px;
  background: hsl(268, 76%, 99%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  max-width: 350px;
  width: calc(100% - 20px);
  box-shadow: 0 2px 5px hsla(268, 56%, 30%, 20%);
}

input {
  border: none;
  padding: 10px 0;
  background: transparent;
  outline: none;
  margin-bottom: 20px;
  width: 100%;
  border-bottom: 2px solid hsl(268, 76%, 40%);
  font-size: 18px;
  color: hsl(268, 40%, 20%);
}

input::placeholder {
  color: hsl(268, 20%, 80%);
  font-weight: 300;
}

button {
  padding: 10px 30px;
  border: none;
  outline: none;
  background: hsl(268, 76%, 29%);
  color: hsl(268, 76%, 99%);
  border-radius: 38px;
  width: calc(100% - 40px);
  margin-top: 30px;
  font-size: 15px;
  cursor: pointer;
  transition: all 0.2s ease-in-out;
}

button:hover {
  background: hsl(268, 76%, 34%);
}

h1 {
  color: hsl(268, 76%, 29%);
  font-weight: 400;
  margin: 0 0 50px 0;
  font-size: 30px;
  text-transform: uppercase;
  align-self: flex-start;
  position: relative;
}

h1:before {
  content: '';
  position: absolute;
  height: 25px;
  width: 3px;
  background: hsl(268, 76%, 29%);
  left: -30px;
  top: 5px;
}
</style>

This code is just for markup and styling, no logic yet.

If you run this app using vue serve App.vue, you'll see a login page with email and password inputs. Submitting the form does nothing yet, but we'll implement this later.

Installing and initializing CometChat

To use CometChat, you have to install it and initialize it first. So run this from your terminal:

npm install --save @cometchat-pro/[email protected]

Import CometChat at the top of the script section.

import { CometChat } from '@cometchat-pro/chat'

Next, we'll initialize it inside the logIn method.

methods: {
  async logIn () {
    if (!CometChat.isInitialized()) {
      const appId = 'your-app-id'
      try {
        await CometChat.init(appId)
        console.log('CometChat was initialized successfully!')
      } catch (e) {
        console.log('An error occured while initializing CometChat')
      }
    }
  }
}

Initializing CometChat is as simple as calling CometChat.init(appId) with your appId. But note that we first have to check that it hasn't already been initialized using CometChat.isInitialized().

To make sure everything works, fill anything in the fields then click LOG IN. You should see "CometChat was initialized successfully!" in the browser's console.

Logging the user in

To log the user in, we have to send a request to the /login endpoint we implemented in the Express app. Since the app is running on port 3000, our request url would look like this:

http://localhost:3000/login?email=${this.email}&password=${this.password}

Send this request using the browser's fetch API.

const response = await fetch(`http://localhost:3000/login?email=${this.email}&password=${this.password}`)

After this, let's check if the response was an error. If it was, let's display a message telling that the email or the password is wrong.

const response = await fetch(`http://localhost:3000/login?email=${this.email}&password=${this.password}`)
if (!response.ok) {
  alert('Wrong email or password!')
} else {}

Note that I'm not checking the type of the error here, I'm just assuming that it is an unauthorized error. But in production, your error checks should be more robust.

Now in the else section, let's get the logged-in user's data, and use the auth token for logging in to CometChat.

const response = await fetch(`http://localhost:3000/login?email=${this.email}&password=${this.password}`)
if (!response.ok) {
  alert('Wrong email or password!')
} else {
  const user = await response.json()
  await CometChat.login(user.cometchatAuthToken)
  alert('Logged in successfully!')
}

After all these changes, your logIn method should look like this:

methods: {
  async logIn () {
    if (!CometChat.isInitialized()) {
      const appId = 'your-app-id'
      try {
        await CometChat.init(appId)
        console.log('CometChat was initialized successfully!')
      } catch (e) {
        console.log('An error occured while initializing CometChat')
      }
    }

    const response = await fetch(`http://localhost:3000/login?email=${this.email}&password=${this.password}`)
    if (!response.ok) {
      alert('Wrong email or password!')
    } else {
      const user = await response.json()
      await CometChat.login(user.cometchatAuthToken)
      alert('Logged in successfully!')
    }
  }
}

As you can see in the code above, we avoided using the secret key with the user UID to log the user in. We instead used the token that we received from the Express server.

The client app is now ready for testing. So try to enter a wrong email or password and you would see an alert dialog saying "Wrong email or password!". But if your email and password are correct (in this case, they should be [email protected]/password), the alert should say "Logged in successfully!".

Recap

To log users in to your CometChat app, call the CometChat.login method with the user UID and the secret key. That would do it. But this is the less-secure way as it uses the secret key in the client code.

To solve this problem, you can use the auth token instead of the UID and the secret key. To get this token, you should ask the backend to generate this auth token for you. The backend generates it using the create-auth token endpoint from the CometChat API. So the backend receives this auth token and passes it to the client app to use it in the CometChat.login method.

Remember, all of this has nothing to do with your app authentication. You still have to handle your app authentication separately. But typically you would need your users to log in to your app first before handing the client the auth token to log in to CometChat.