Authorization

pluv.io uses JWTs to authorize access to rooms on a new connection. To generate a JWT, you will need to setup an authentication endpoint to determine if the user should have access to the room.

The examples below will use express, but so long as you can create an http endpoint that can return text responses, these should still be relevant.

Enable authorization on io

Set the authorize property on your createIO config to enable authorization on your io instance.

1// server/io.ts
2
3import { createIO } from "@pluv/io";
4import { platformNode } from "@pluv/platform-node";
5import { z } from "zod";
6
7export const io = createIO({
8 authorize: {
9 // If required is false, users can authenticate for a room to
10 // attach an identity to their presence. Otherwise they will be
11 // anonymous.
12 required: true,
13 // The secret for generating your JWT
14 secret: process.env.PLUV_AUTH_SECRET!,
15 // The shape of your user object. `id` must always be required.
16 user: z.object({
17 id: z.string(),
18 // Here is an additional field we wish to add.
19 name: z.string(),
20 }),
21 },
22 platform: platformNode(),
23});
24
25export type AppPluvIO = typeof io;

Setup an authorization endpoint

To add custom authorization, you'll need to define an http endpoint to return a JWT from.

1// server/server.ts
2
3import express from "express";
4import Http from "http";
5import { io } from "./io";
6
7const PORT = 3000;
8
9const app = express();
10const server = Http.createServer();
11
12app.get("/api/authorize", async (req, res) => {
13 const room = req.query.room as string;
14
15 // ... Implement your custom authorization here
16
17 const token = await io.createToken({
18 room,
19 user: {
20 id: "abc123",
21 name: "leedavidcs",
22 },
23 });
24
25 return res.send(token).status(200);
26});
27
28server.listen(PORT, () => {
29 console.log(`Server is listening on port: ${port}`);
30});

Connect to your authorization endpoint

Now that we have our endpoint defined, connect our frontend client to our authorization endpoint.

1// frontend/io.ts
2
3import { createClient } from "@pluv/react";
4import type { AppPluvIO } from "server/io";
5
6const client = createClient<AppPluvIO>({
7 // Specify your auth endpoint here
8 authEndpoint: (room) => `http://localhost:3000/api/authorize?room=${room}`,
9 // Define a ws endpoint url based on how you parse the room name
10 wsEndpoint: (room) => `ws://localhost:3000/api/room/${room}`,
11});

How to use POST requests

1// frontend/io.ts
2
3import { createClient } from "@pluv/react";
4import type { AppPluvIO } from "server/io";
5
6const client = createClient<AppPluvIO>({
7 authEndpoint: (room) => ({
8 url: "http://localhost:3000/api/authorize",
9 // You can use fetch options as well like so
10 options: {
11 method: "POST",
12 body: JSON.stringify({ room }),
13 },
14 }),
15 // Define a ws endpoint url based on how you parse the room name
16 wsEndpoint: (room) => `ws://localhost:3000/api/room/${room}`,
17});

Add token to room registration

When the frontend receives a JWT from your authorization endpoint, it will add that token as a token query parameter to your websocket connection request. To use this token, pass the token into io.room.register on your server.

1import express from "express";
2import Http from "http";
3import WebSocket from "ws";
4import { io } from "./io";
5
6const PORT = 3000;
7
8const app = express();
9const server = Http.createServer();
10const wsServer = new WebSocket.Server({ server });
11
12const parseRoomId = (url: string): string => {
13 /* get room from req.url */
14};
15
16const parseToken = (url: string): string => {
17 /* get token from query parameters of req.url */
18};
19
20wsServer.on("connection", async (ws, req) => {
21 const roomId = parseRoomId(req.url);
22 const token = parseToken(req.url);
23
24 // Pass in the token from query params
25 await room.register(ws, { token });
26});
27
28app.get("/api/authorize", async (req, res) => {
29 const room = req.query.room as string;
30
31 // ... Implement your custom authorization here
32
33 const token = await io.createToken({
34 room,
35 user: {
36 id: "abc123",
37 name: "leedavidcs",
38 },
39 });
40
41 return res.send(token).status(200);
42});
43
44server.listen(PORT, () => {
45 console.log(`Server is listening on port: ${port}`);
46});