In this tutorial, we will be building a chat application with role-based authentication using React and Strapi version 4. We will cover the following topics:
1. Setting up the project
2. Creating a user registration form
3. Implementing email verification
4. Building the login system
5. Role-based authentication
6. Creating a chat room with socket.io
7. Implementing role-based access control (RBAC)
8. Testing and deployment
By the end of this tutorial, you will have built a fully functional chat application with user registration, email verification, login system, role-based authentication, and real-time messaging capabilities.
To follow along with this tutorial, you should have basic knowledge of React, Node.js, Express, and MongoDB. You can also refer to the GitHub repository for the complete code: https://github.com/AustinOsuji/chat-app-strapi-react
Let's get started!
1. Setting up the project
First, create a new React app using Create React App:
```bash
npx create-react-app chat-app
cd chat-app
```
Next, install the following dependencies:
```bash
npm install axios antd socket.io-client styled-components
```
2. Creating a user registration form
Create a new file `UserForm.js` in the `src` directory and add the following code:
```javascript
import React, { useState } from "react";
import { Input, Button, Form } from "antd";
import { UserOutlined, LockOutlined } from "@ant-design/icons";
import axios from "axios";
const UserForm = () => {
const [form] = Form.useForm();
const onFinish = (values) => {
console.log("Received values of form: ", values);
axios
.post("http://localhost:1337/api/auth/local/register", {
username: values.username,
email: values.email,
password: values.password,
})
.then((response) => {
console.log(response);
alert("Registration successful!");
})
.catch((error) => {
console.log(error);
alert("An error occurred during registration.");
});
};
return (
<Form form={form} name="register" onFinish={onFinish}>
<Form.Item
name="username"
rules={[{ required: true, message: "Please input your username!" }]}
>
<Input prefix={<UserOutlined />} placeholder="Username" />
</Form.Item>
<Form.Item
name="email"
rules={[{ type: "email", message: "Please input a valid email!" }]}
>
<Input prefix={<MailOutlined />} placeholder="Email" />
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: "Please input your password!" }]}
>
<Input.Password prefix={<LockOutlined />} placeholder="Password" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Register
</Button>
</Form.Item>
</Form>
);
};
export default UserForm;
```
3. Implementing email verification
To implement email verification, we will use the `nodemailer` package to send emails with a unique token for each user during registration. Create a new file `sendEmail.js` in the `src` directory and add the following code:
```javascript
import nodemailer from "nodemailer";
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.EMAIL,
pass: process.env.EMAIL_PASSWORD,
},
});
export const sendVerificationEmail = async (user) => {
try {
const token = crypto.randomBytes(20).toString("hex");
await axios.post("http://localhost:1337/api/auth/local/send-verification-email", {
email: user.email,
url: `${process.env.CLIENT_URL}/verify?token=${token}`,
});
const info = await transporter.sendMail({
from: process.env.EMAIL,
to: user.email,
subject: "Verify your email",
text: `Please click on the following link to verify your email: ${process.env.CLIENT_URL}/verify?token=${token}`,
});
console.log("Email sent:", info.response);
} catch (error) {
console.error(error);
}
};
```
4. Building the login system
Create a new file `LoginForm.js` in the `src` directory and add the following code:
```javascript
import React, { useState } from "react";
import { Input, Button, Form } from "antd";
import { UserOutlined, LockOutlined } from "@ant-design/icons";
import axios from "axios";
const LoginForm = () => {
const [form] = Form.useForm();
const onFinish = (values) => {
console.log("Received values of form: ", values);
axios
.post("http://localhost:1337/api/auth/local", {
identifier: values.email,
password: values.password,
})
.then((response) => {
console.log(response);
alert("Login successful!");
})
.catch((error) => {
console.log(error);
alert("An error occurred during login.");
});
};
return (
<Form form={form} name="login" onFinish={onFinish}>
<Form.Item
name="email"
rules={[{ required: true, message: "Please input your email!" }]}
>
<Input prefix={<MailOutlined />} placeholder="Email" />
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: "Please input your password!" }]}
>
<Input.Password prefix={<LockOutlined />} placeholder="Password" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Login
</Button>
</Form.Item>
</Form>
);
};
export default LoginForm;
```
5. Role-based authentication
To implement role-based authentication, we will use the `jwt-simple` package to generate JWT tokens with user roles during login. Create a new file `generateToken.js` in the `src` directory and add the following code:
```javascript
import jwt from "jwt-simple";
import moment from "moment";
const secret = process.env.SECRET;
export const generateToken = (user) => {
const expirationTime = moment().add(1, "days").unix();
const token = jwt.encode({ user, exp: expirationTime }, secret);
return token;
};
```
6. Creating a chat room with socket.io
To create a real-time chat room, we will use the `socket.io` package to establish a WebSocket connection between the client and server. Create a new file `chat.js` in the `src` directory and add the following code:
```javascript
import React from "react";
import { Input } from "antd";
import "antd/dist/antd.css";
import "font-awesome/css/font-awesome.min.css";
import Header from "./Header";
import Messages from "./Messages";
import List from "./List";
import socket from "socket.io-client";
function ChatRoom() {
return (
<ChatContainer>
<Header room="Group Chat" />
<StyledContainer>
<List users={users} id={id} username={username} />
<ChatBox>
<Messages messages={messages} username={username} />
<Input
type="text"
placeholder="Type your message"
value={message}
onChange={handleChange}
/>
<StyledButton onClick={handleClick}>
<SendIcon>
<i className="fa fa-paper-plane" />
</SendIcon>
</StyledButton>
</ChatBox>
</StyledContainer>
</ChatContainer>
);
}
export default ChatRoom;
```
7. Implementing role-based access control (RBAC)
To implement RBAC, we will use the `express-jwt` package to protect certain routes based on user roles. Create a new file `authMiddleware.js` in the `src` directory and add the following code:
```javascript
import jwt from "jsonwebtoken";
import dotenv from "dotenv";
dotenv.config();
export const authMiddleware = (req, res, next) => {
try {
const token = req.headers.authorization.split(" ")[1];
const decodedToken = jwt.verify(token, process.env.SECRET);
req.userData = decodedToken;
next();
} catch (error) {
res.status(401).json({ message: "Invalid token" });
}
};
```
8. Testing and deployment
To test the chat application, run the following commands in separate terminal windows:
- `npm start` to start the React client
- `npm run server` to start the Strapi server
You can now access the chat application at http://localhost:3000. To deploy the application, you can use platforms like Heroku or Vercel.
That's it! You have successfully built a chat application with role-based authentication using React and Strapi version 4.