Invite Only Chat with Laravel and Vue

Group chat can get a bit messy, especially if it’s public and anyone can join. Making a group chat invite-only can help manage the content of the group and the sanity of those in it, in addition to preventing spam users and bots.

In this tutorial, we’ll be building an invite-only chat room where only admin users can invite other users to join a chat room. Upon joining the chat room, users will be able to chat with other users in realtime.

The complete code for this tutorial is available on GitHub.

Prerequisites

To complete this tutorial, you'll need the following tech:

To follow along with this tutorial, a basic understanding of Laravel, Vue.js, and JavaScript would also be helpful.

Getting Our Stream Chat Keys

To use Stream Chat in our app, we need to grab our Stream Chat API keys. Stream Chat allows you to build a fully-functional chat app in hours, instead of weeks, or even months; we'll use it to build our simple example app in minutes! To get started log in to Stream or create an account. Upon successfully entering your credentials, you'll be delivered to your dashboard, where you can create a new app by clicking the Create App button:

Screenshot of the Modal to Create a New Stream Chat App

Once that is done, you should see an API KEY and SECRET for your newly created application:

Screenshot of the Stream Chat Dashboard

Take note of these keys as we’ll be needing them shortly.

Getting Started

We’ll be using the Laravel installer to create a new Laravel application. Run the following command to create a new Laravel application with authentication scaffolding:

https://gist.github.com/nparsons08/a9f1d9a9ba8a427e0b57ebabbc7070a0

Once that’s done, let’s install the npm dependencies:

https://gist.github.com/nparsons08/b6cf3e8b7a7c0877aea42520000059d1

Now, we can begin building out our application!

Building the Application

We’ll start by updating the users table migration in our create_users_table.php file, within database/migrations, as shown below:

https://gist.github.com/BrightnBubbly/70cca59f62e82dc1bcaca6db9589d63a

We updated the name field to username and added a new field called is_admin, which will be used to determine if a user is an admin or not.

Let’s update the fillable fields in our User.php file, in the app directory, to have the username field instead, as well:

https://gist.github.com/BrightnBubbly/09956581d2473e27e55ba212ed1c8344

Next, we’ll create an Invite model:

https://gist.github.com/nparsons08/de3bb11a4bee853c27078b800c226b64

In addition to creating an Invite model, the command above will create a migration, as well as a controller for the model.

Open up the created migration and update the up method in the create_invites_table.php file, within database/migrations, as shown below:

https://gist.github.com/BrightnBubbly/73cd54da849369ddd335ab164c99a8ee

The fields are pretty straightforward; the accepted field will be used to determine if an invite has been accepted or not.

Also, let’s mark the fields as fillable in Invite.php, in the app directory:

https://gist.github.com/BrightnBubbly/e78599a3588ec7a08e9fd8064ebc6ba3

Before we run the migration, let’s set up our database. For the purpose of this tutorial, we’ll be using SQLite. Update DB_CONNECTION inside .env as below:

https://gist.github.com/nparsons08/495bcafffc302595d0799bd1228ff2ee

Because we are making use of SQLite, we can get rid of the other DB environment variables.

By default, Laravel will look for a database.sqlite file, so let’s create it:

https://gist.github.com/nparsons08/7033d262d70ddea923382ffcc7def34b

Now, we can run the migration:

https://gist.github.com/nparsons08/3df108cef810c83911d9e91cbb9b7e62

Before we move on to adding functionality to our application, let’s add our Stream keys to our .env file:

https://gist.github.com/nparsons08/eb3ad477455c23e06a9ed632b8530c26

Be sure to update "YOUR_STREAM_API_KEY" and "YOUR_STREAM_API_SECRET" to the values you grabbed from your Stream Chat dashboard.

Creating Channel and Admin Users

Now, let’s start building the group chat functionality. We’ll start by creating a new channel, which we’ll call "Chatroom", and an admin user, to administer the group. We’ll be creating a console command to handle these. Run the command below to create a new console command:

https://gist.github.com/nparsons08/81945ee7f07471950c1b2878acea9428

This will create a new InitializeChannel.php file inside app/Console/Commands.

Since we’ll be making use of the Stream Chat PHP SDK, let’s install it:

https://gist.github.com/nparsons08/3ca796a6f46ac5b970e539e86b342b58

With that installed, open up InitializeChannel.php, located at app/Console/Commands, and replace the contents with the following:

https://gist.github.com/BrightnBubbly/b57b28c05a725468ade3dd191e6bc21c

We define the signature of the command and give it a description. Inside the handle method, we create an admin user, then we create the user on Stream as well, assigning the user an admin role. Then, we create the channel and make the newly created user the creator of the channel. Next, we add the user as a member of the channel. Lastly, we return a success message.

Now, we can run the channel:init command:

https://gist.github.com/nparsons08/efe3c2b7c79e3cba5eda08a9c9a557e5

Since we want users to join our group chat only by invitation, let’s remove the ability to register, which was added by Laravel authentication scaffolding. We can do that by updating web.php, in the routes directory, with the below:

https://gist.github.com/nparsons08/ec2b134e3c4aed1dc706d4fd7a95659f

Inviting Users

With the channel and admin users created, let’s add the functionality to invite users to our group chat. We’ll start by creating the routes. Add the code below inside web.php:

https://gist.github.com/nparsons08/8560f1e03898eef20579c45f59cf8f06

Since we already have InviteController.php, let’s open it up and add the following code in it:

https://gist.github.com/BrightnBubbly/3bf0e3f5cfe6569839c0debf6ae9d69d

Next, let’s create the view file. Inside the resources/views directory, create a new invites directory and create a create.blade.php file inside it, then paste the following code in it:

https://gist.github.com/BrightnBubbly/0c15a741ad6f1f06ab50b3efa267630e

The form has just one field, which is for capturing the email address to send an invitation to. Above the form, we have in place to display flash messages, if there are any:

Screenshot of the Invite User Page

Let’s move on to adding the implementation for processing the form. Add the following code to the top of InviteController.php:

https://gist.github.com/BrightnBubbly/87ed322b87ea94a642544d60a57e9c2f

First, we get an invite matching the submitted email address. If an invite already exists for the email address, we flash an appropriate message depending on whether the invite as been accepted or not. If no invite was found, we create one for the email address, then send an email with the invitation link.

For this tutorial, we won’t be setting up a mail driver. Instead, we’ll log the mail to a file. Let’s set the MAIL_MAILER to "log" inside .env as shown below:

$ MAIL_MAILER=log

Now, if we try sending an invite, it should be logged inside storage/logs/laravel.log and look something like the below:

https://gist.github.com/BrightnBubbly/63394627a90277eda6525e22e8ca9700

I’m using Laravel Valet, hence my URL: http://stream-invite-only-group-chat.test

Let’s add a link to access the invite users page. We’ll add it in the navbar (app.blade.php) immediately after the @else:

https://gist.github.com/BrightnBubbly/2b3f2e4bf1cd5783c3a8bc04cc0ae626

While we are here, let’s update the navbar to show the user’s username instead of the name:

https://gist.github.com/nparsons08/757689a7892fb1f5a9e26078e363c188

With these changes, your navbar should look like the below:

Screenshot of the Navbar with Link to Invite Page and User's Username

Joining Group Chat through Invitation Link

Once a user is sent an invitation, the user can click on the link in the email to join the group chat. To make this possible, add the following code inside web.php:

https://gist.github.com/nparsons08/816733f4be7ddba1f614405946e1dc52

Next, add the following code inside InviteController.php:

https://gist.github.com/BrightnBubbly/fe45bfd2ae3c8c26bf6923e0d6a030a8

First, we retrieve the invite matching the token, if it exists. If the invitation has been accepted, we simply redirect the user to the home route. Otherwise, we render the "register" view and pass along the invite.

The register view is already in place; we just need to update it slightly. Replace the name and email fields in resources/views/auth/register.blade.php as below:

https://gist.github.com/BrightnBubbly/5415bb17a8d76cb292117c11298a7ff2

We made the email field read-only and set the value to the email address on the invite.

Screenshot of the Register Page with Preset Email

We’ll still make use of the default Laravel RegisterController, at app/Http/Controllers/Auth/, to handle registration. Open it up and update validator and create methods to make use of username instead of name like below:

https://gist.github.com/BrightnBubbly/ba1dd8c0b071e4afa5f1b5214997d438

Still inside RegisterController.php, add the following code to the very top:

https://gist.github.com/BrightnBubbly/e75cc20d7411c62ac25dd6cda54657aa

Once a user registers successfully, the registered method is called. Inside this method is the perfect place to mark the invite as accepted, create the user on Stream, and, finally, add the user to the "Chatroom" channel.

Generating an Authentication Token

Let’s add the functionality for generating an authentication token, which Stream Chat will use to authenticate a user.

First, let’s create the endpoint inside routes/api.php:

https://gist.github.com/nparsons08/0c6cfe0c4b87f807a2bc412ab0bc990f

Next, create a TokenController:

https://gist.github.com/nparsons08/ea22d2d48eaf8f6f158f47a1ccb4e44d

and add the following to it:

https://gist.github.com/BrightnBubbly/e2b8815fac25a7bbb08ac09d7086beed

This generates a token using the user’s username as the ID.

Adding Chat Functionality

With the backend functionality in place, let’s move on to adding the chat functionality. We are going to rename ExampleComponent.vue, inside the resource/js directory, to "ChatRoom.vue" and update its reference inside resources/js/app.js as below:

https://gist.github.com/nparsons08/15f582e6c653743200b45150cb98aabe

Now, replace the content of the ChatRoom component with the following:

https://gist.github.com/BrightnBubbly/e05eeeeeac1951b3933bcdb947ab53d3

The template is made up of two parts: the members list and the chat itself. We generate a token for the authenticated user, then we use the token to instantiate the Stream Chat client. We also initialize the channel and watch for activities on the channel, which allows us to know when a new message is sent on the channel as well when new users join the channel. Lastly, we have the functionality for sending a new message.

For a guide that covers these in detail, check out my previous tutorial.

Now, let’s install the Stream Chat JavaScript SDK:

https://gist.github.com/nparsons08/f85af5a1ce8bf7242a11ede622c01789

Next, let’s make use of the ChatRoom component. Update home.blade.php as shown below:

https://gist.github.com/BrightnBubbly/45cb1d5d62b3b1fa2a913544261abc1b

The ChatRoom component accepts the authenticated user as props, which we are passing in.

Screenshot of the Chatroom Page

Securing Our Application

Remember we said only an admin user can invite users to join our chatroom? But, as it stands, anybody can do this, even if they're not logged in. Let’s change that! Laravel provides an Authenticate middleware, by default, which we can use to enforce access to only authenticated users. We’ll create another middleware for enforcing an authenticated user is an admin.

Run the command below to create an Admin middleware:

https://gist.github.com/nparsons08/7451d2ebb8bfa35d36a5e4369b0c2f29

and update the handle method as shown below:

https://gist.github.com/BrightnBubbly/07227d49dacfea89fb24375db98ab1dc

Here, we are simply redirecting the authenticated user to the home route if the user is not an admin. If they are an admin, we allow the user to access the requested page.

Before we can make use of the middleware, we need to register it. We’ll register it as a route middleware by adding it inside the $routeMiddleware array, in app/Http/Kernel.php, like so:

https://gist.github.com/nparsons08/13a1ba20e709a42125a28390448fd7b5

Now, we can make use of the middleware inside web.php using the admin key/identifier:

https://gist.github.com/nparsons08/6c0ab6ea9b0ac3786186fb87387ed2de

Now, not only does a user have to be authenticated to access these routes, but they must also be an admin!

Wrapping Up

In this tutorial, we have seen how to build an invite-only group chat using Laravel, Vue.js, and Stream Chat. We created multiple pages and authentication layers to our simple chat, but there is so much more you can do! To learn more about Stream Chat and its exciting features, check out the docs!

Thanks for reading, and happy coding!

TutorialsChat