[]
        
(Showing Draft Content)

User Authentication and Permissions

This guide will teach you to implement user authentication and message permission validation in js-collaboration. Middleware is used to verify user identity, and upon receiving messages, permissions are checked to determine whether operations are allowed.

Summary

js-collaboration enforces secure authentication through token validation while implementing message-level permission controls. This ensures:

  • Only authenticated clients establish server connections.

  • Message handling permissions are enforced via policies.

Key Points:

  • Authentication: User identity is verified through tokens to ensure the client is a legitimate user.

  • Permission Validation: Message permission control is achieved by storing and retrieving user information.

type=warning

The token validation and permission validation in this example are for demonstration purposes only. In real-world applications, more secure and complex validation mechanisms should be implemented based on business requirements.

Workflow

Client

  1. The user logs in and obtains a token.

  2. The client passes the token as an auth parameter to the server via client.connect().

  3. The server receives the token and performs validation. If authentication is successful, the client establishes a connection with the server; otherwise, an authentication failure message is returned.

Server

  1. The server retrieves and validates the token passed by the client through the server.use() middleware.

  2. If authentication is successful, the server stores the user information in connection.tags and allows the client to perform subsequent operations (e.g., sending messages).

  3. If authentication fails, the server returns an error message, which the client can receive.

Client-Side: Send Authentication Information

On the front end, the client needs to pass the token as an auth parameter to the server during connection establishment. Below is an example of how to send authentication information on the client side.

The front end passes the token to the server for authentication via the client.connect() method.

import { Client } from '@mescius/js-collaboration-client';

// Simulate login
async function login(username, password) {
    const response = await fetch('http://localhost:8080/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ username, password })
    });
    const result = await response.json();
    if (result.success) {
        return result.token;
    } else {
        throw new Error(result.message);
    }
}

// Obtain token
const userToken = await login('reader1', 'read123');

// Create client instance and connect to room
const client = new Client('ws://localhost:8080');
const connection = client.connect('room123', {
    auth: {
        token: userToken
    }
});

Code Explanation

  • The client passes userToken as an auth parameter to the server for authentication.

  • The server validates the token through middleware and either allows or denies the connection based on the validation result.

Server-Side: Authentication and Message Permissions

On the server side, we use middleware to verify the token passed by the client and perform relevant operations based on the verified user information.

  • In the connect middleware, we retrieve and validate the token passed by the client and store the user information in connection.tags.

  • In the message middleware, we retrieve the user information from connection.tags and perform permission checks.

import express from 'express';
import { createServer } from 'http';
import { Server } from '@mescius/js-collaboration';
import jwt from 'jsonwebtoken';

const app = express();
const httpServer = createServer(app);
const server = new Server({ httpServer });

app.use(express.json());

// JWT secret key
const JWT_SECRET = 'your-secret-key-here';

// Simulated user database
const users = new Map([
    ['admin1', { username: 'admin1', password: 'admin123', role: 'admin' }],
    ['reader1', { username: 'reader1', password: 'reader123', role: 'reader' }],
    ['editor1', { username: 'editor1', password: 'editor123', role: 'editor' }]
]);

// Login route
app.post('/login', (req, res) => {
    const { username, password } = req.body;

    const user = users.get(username);
    if (!user || user.password !== password) {
        return res.status(401).json({
            success: false,
            message: 'Invalid username or password'
        });
    }

    const token = jwt.sign(
        { username: user.username, role: user.role },
        JWT_SECRET
    );

    res.json({
        success: true,
        token,
        user: { username: user.username, role: user.role }
    });
});

server.use('connect', async (context, next) => {
    const token = context.connection.auth?.token;

    if (!token) {
        await next('No token provided');
        return;
    }

    try {
        const decoded = jwt.verify(token, JWT_SECRET);
        const user = {
            username: decoded.username,
            role: decoded.role
        };
        context.connection.tags.set('user', user);
        console.log(`User authenticated: ${user.username} (${user.role})`);
        await next();
    } catch {
        await next('Invalid token');
    }
});

server.use('message', async ({ connection }, next) => {
    const user = connection.tags.get('user');
    if (user.role === 'admin' || user.role === 'editor') {
        await next();
    } else {
        await next('no edit permission');
    }
});

// Start the server
httpServer.listen(8080);

Code Explanation

  • Authentication Validation: In the connect middleware, the token passed by the client is retrieved via context.connection.auth?.token and validated. If validation passes, the user information is retrieved and stored in connection.tags.

  • Permission Validation: In the message middleware, the stored user information is retrieved via context.connection.tags.get('user'), and message permission validation is performed based on the user’s role.