# User Authentication and Permissions

## Content

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()](/spreadjs/api/collaboration/js-collaboration-client/classes/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()](/spreadjs/api/collaboration/js-collaboration/classes/Server#use) middleware.
2. If authentication is successful, the server stores the user information in [connection.tags](/spreadjs/api/collaboration/js-collaboration/classes/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.

```typescript
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.

```typescript
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.