Embedding Rocket Chat using iFrame Auth

Recently I was working on a project where I had to embed Rocket.chat on a website, and when the user login to the website, they will also get automatically logged-into Rocket.chat

The following steps have to be performed:

  1. Check if the user exists in Rocket.chat
  2. If the user exists then login user
  3. If the user doesn’t exist then create the user in Rocket. chat and log in the user

I went through the Rocket chat documentation and figured out the best way to do it would be through a combination of iFrame Auth and the Rocket chat REST API. The iFrame Auth will be used to perform login and Rocket chat REST API to create a new user and generate tokens, but the documentation regarding the iFrame Auth was not quite clear and it was confusing, I also studied the provided example code and then after some fiddling I was able to implement my solution and I will walk you through the steps:

Login, Create Account and Server Setup

When doing iFrame Auth, Rocket chat sends few requests to our server so we will have to create few API’s on our server that Rocket chat server would call to authenticate the user.  I am using Node.JS + Express on the server side in the following example but the logic is similar even if you are using a different server or programming language.

Creating a wrapper to encapsulate Rocket chat API

We will call the Rocket Chat API to create a user in Rocket chat and we will also use it to Login the user and get the token.

First, we will have to obtain Rocket Chat Admin UserID and Admin Auth Token, this can be done by simply calling the Rocket Chat Login API:

curl http://localhost:3000/api/v1/login \
     -d "username=myusername&password=mypassword"

 

Here http://localhost:3000 is the Rocket Chat URL and in place of myusername enter your Rocket chat admin username and under mypassword enter your password.

You’ll get a response something like this

{
  "status": "success",
  "data": {
      "authToken": "9HqLlyZOugoStsXCUfD_0YdwnNnunAJF8V47U3QHXSq",
      "userId": "aobEdbYhXfu5hkeqG",
      "me": {
            "_id": "aYjNnig8BEAWeQzMh",
            "name": "Rocket Cat",
            "emails": [
                {
                  "address": "rocket.cat@rocket.chat",
                  "verified": false
                }
            ],
            "status": "offline",
            "statusConnection": "offline",
            "username": "rocket.cat",
            "utcOffset": -3,
            "active": true,
            "roles": [
                "admin"
            ],
            "settings": {
                "preferences": {}
              }
        }
   }
}

 

Extract authToken and userId from the above response as we would need it in the next step.

Now we have to authToken and userId of the Rocket chat admin, we can use this to call Rocket Chat API and create new users in Rocket Chat.

import request from 'request-promise-native'

const rocketChatServer = 'http://localhost:3000';
const rocketChatAdminUserId = 'aobEdbYhXfu5hkeqG';
const rocketChatAdminAuthToken = '9HqLlyZOugoStsXCUfD_0YdwnNnunAJF8V47U3QHXSq';

export async function fetchUser (username) {
  const rocketChatUser = await request({
    url: `${rocketChatServer}/api/v1/users.info`,
    method: 'GET',
    qs: {
      username: username
    },
    headers: {
      'X-Auth-Token': rocketChatAdminAuthToken,
      'X-User-Id': rocketChatAdminUserId
    }
  });
  return rocketChatUser;
}

export async function loginUser (email, password) {
  const response = await request({
    url: `${rocketChatServer}/api/v1/login`,
    method: 'POST',
    json: {
      user: email,
      password: password
    }
  });
  return response;
}

export async function createUser(username, name, email, password) {
  const rocketChatUser = await request({
    url: `${rocketChatServer}/api/v1/users.create`,
    method: 'POST',
    json: {
      name,
      email,
      password,
      username,
      verified: true
    },
    headers: {
      'X-Auth-Token': rocketChatAdminAuthToken,
      'X-User-Id': rocketChatAdminUserId
    }
  });
  return rocketChatUser;
}

export async function createOrLoginUser (username, name, email, password,) {
  try {
    const user = await fetchUser(username);
    // Perfom login
    return await loginUser(email, password);
  } catch (ex) {
    if (ex.statusCode === 400) {
      // User does not exist, creating user
      const user = await createUser(username, name, email, password);
      // Perfom login
      return await loginUser(email, password);
    } else {
      throw ex;
    }
  }
}

The above code snippet we have created a few methods that are very self-descriptive. We will use these methods to create and login user into the Rocket Chat when user login to our server.

Creating API’s

import { createOrLoginUser } from 'server/rocketchat';


app.post('/login', (req, res) => {
// ....CODE TO LOGIN USER

    // Creating or login user into Rocket chat 
   try {
    const response = await createOrLoginUser(user.username, user.firstName, user.email, user.password);
    req.session.user = user;
    // Saving the rocket.chat auth token and userId in the database
    user.rocketchatAuthToken = response.data.authToken;
    user.rocketchatUserId = response.data.userId;
    await user.save();
    res.send({ message: 'Login Successful'});
   } catch (ex) {
     console.log('Rocket.chat login failed');
   }
})

// This method will be called by Rocket.chat to fetch the login token
app.get('/rocket_chat_auth_get', (req, res) => {
  if (req.session.user && req.session.user.rocketchatAuthToken) {
    res.send({ loginToken: ctx.session.user.rocketchatAuthToken })
    return;
  } else {
    res.status(401).json({ message: 'User not logged in'});
    return;
  }
})

// This method will be called by Rocket.chat to fetch the login token
// and is used as a fallback
app.get('/rocket_chat_iframe', (req, res) => {
const rocketChatServer = 'http://localhost:3000';
  if (req.session.user && req.session.user.rocketchatAuthToken) {
    // We are sending a script tag to the front-end with the RocketChat Auth Token that will be used to authenticate the user
    return res.send(`<script>
      window.parent.postMessage({
        event: 'login-with-token',
        loginToken: '${ req.session.user.rocketchatAuthToken }'
      }, '${ rocketChatServer }');
    </script>
    `)
    return;
  } else {
    return res.status(401).send('User not logged in')
  }
})

In the above code snippet, we are creating routes that Rocket Chat will call to fetch the login token and authenticate the user, in the next step we will update the Rocket Chat Setting and include these routes.

Setting up Rocket Chat

There are few configurations that we have to make in Rocket chat to get it working with iFrame Auth.

Step 1:

Go under Accounts->iFrame and update the settings as per the screen-shot below Here we are specifying the routes that we had created in the previous step. http://localhost:8080 is where our local Node.JS server is running.

Step 2:

Go under General->iFrame Integration and update the settings as per the screenshot 

Embedding Rocket Chat

Now, after the setting on Rocket chat is done, we will embed Rocket chat into our web page, now embedding Rocket Chat is as simple as adding the iFrame on the page you want to embed

See the example below

<html>
  <body>
    <iframe width='100%;' height='100%' src="http://localhost:3000/channel/general?layout=embedded" frameborder="0"></iframe>
  </body>
</html>

Here http://localhost:3000 is the address of the Rocket Chat server and adding ?layout=embedded shows are cleaner UI.

Conclusion

That’s’ it! Let me know if you have any questions or suggestions in the comments below.


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *