Skip to main content

User authentication

In order to use the collab service, users must be signed in and authenticated with the server.

The server supports two methods of authentication: token based authentication, and email and password authentication .

In most cases, you will want to use token based authentication, as it is the most flexible.

Read both authentication methods below and choose what one works best for you.

Note

Email and password authentication requires the COLLAB_KEY environment variable to be set. Read more here

Token based authentication#

Token based authentication uses an authentication token that is passed between the server and client. The token is used to validate the users session.

In this flow, you must provide us with a function that accepts an authentication token, and returns a user id. This leaves the token generation and validation totally up to you, making this the most flexible option.

How it works#

You must pass a getUserFromToken function to the server constructor. This function will accept a token, and must return either an object with the users id if the token is valid, or null otherwise.

import CollabServer from '@pdftron/collab-server';
const server = new CollabServer({
getUserFromToken: async (token) => {
const user = await decodeUserFromToken(token);
if (user) {
return { id: user.id };
} else {
return null;
}
}
});

When the user signs in with your application, an authentication token is set by your server (usually in a cookie). This is the token you will use to sign in. The default cookie name is wv-collab-token, you can also overwrite this cookie name by passing jwtCookieName to the server constructor:

const server = new CollabServer({
...otherOptions,
jwtCookieName: 'new-cookie-name'
});

Once the user is logged in to your system and has a token, use the you call the loginWithToken function from the client module, and pass in the token your server generated.

collabClient.loginWithToken(token);

Example#

This example shows one possible way you could handle this flow using JWT. Keep in mind you do not have to use JWT, this is just one possible case.

Server

import CollabServer from '@pdftron/collab-server';
import express from 'express';
import jwt from 'jsonwebtoken';
// this should be an env variable in a real word scenario
const SECRET_KEY = 'ABCEF';
const app = express();
app.use(express.json());
// Create a login endpoint using an express server
app.post('/login', async (req, res) => {
const { email, password } = req.body;
// validate the email and password
// using your own flow
const user = await validateUser(email, password);
if (!user) {
// send 401 unauthorized response if email or pass is invalid
return res.status(401).send();
}
// generate a JWT using the 'jsonwebtoken' package
// here we only encode the users id because thats all that is required
const token = jwt.sign(
{
id: user.id
},
SECRET_KEY
);
// set the cookie and return a valid response
// the cookie name is 'wv-collab-token' by default or your customized jwtCookieName
res.cookie('wv-collab-token', token);
return res.status(200).send({ token });
});
app.listen(3001, () => {
console.log('Listening on port 3001');
});
// create an instance of the collab server,
// and pass in the 'getUserFromToken' option.
const server = new CollabServer({
...otherOptions,
getUserFromToken: async (accessToken) => {
try {
// decode the JWT using the 'verify' function.
const payload = jwt.verify(accessToken, SECRET_KEY);
// if the token is valid, the payload will equal
// {id: 'usersId'}, because this is what
// we encoded in the /login endpoint above
if (payload) {
return payload;
} else {
return null;
}
} catch (e) {
return null;
}
}
});
// start the collab server
server.start(3000);

Client

import CollabClient from '@pdftron/collab-client';
const client = new CollabClient({
...options
});
const submitButton = document.getElementById('loginButton');
// set up an onclick handler for your login form
submitButton.onClick = async () => {
// send the email and password to the /login endpoint (setup above)
const resp = await fetch('http://localhost:3001/login', {
body: {
email: document.getElementById('emailField').value,
password: document.getElementById('passwordField').value
},
method: 'post'
});
if (resp.status === 200) {
const { token } = await resp.json();
// login the collab client with your token
// this will pass the token to the `getUserFromToken` function
// passed to the server, and validate the session
await client.loginWithToken(token);
}
};

Email and password authentication#

Email an password authentication is similar to token authentication, except the collab server handles the token generation, and instead you just verify a email and password.

Once a persons email and password is verified, we generate a JWT and set it as a cookie. This cookie is used to authenticate the user in future requests.

To use this method, an environment variable called COLLAB_KEY must be set to a string. This will be the secret key we use to encode the JWT. Make sure to not share this string with anyone. Treat it like a password!

How it works#

To use email and password authentication, you must pass a verifyPassword function to the constructor. The function accepts a email and password, and must return a promise that resolves to a boolean indicating if the email and password are valid.

import CollabServer from '@pdftron/collab-server';
const server = new CollabServer({
verifyPassword: async (email, password) => {
const user = await myDB.query(`SELECT * FROM users WHERE email = ${email} LIMIT 1`);
if (!user) return false;
const hashedPassword = user.password;
const passwordValid = comparePassword(password, hashedPassword);
return passwordValid;
}
});
server.start(3000);

Now on the client, you call the loginWithPassword function with the users email and password. This gets passed in to your verifyPassword function on the server, and if returns true, the user is logged in!

Example#

Server

import CollabServer from '@pdftron/collab-server';
const server = new CollabServer({
...otherOptions,
verifyPassword: async (email, password) => {
const user = await myDB.query(`SELECT * FROM users WHERE email = ${email} LIMIT 1`);
if (!user) return false;
const hashedPassword = user.password;
const passwordValid = comparePassword(password, hashedPassword);
return passwordValid;
}
});
server.start(3000);

Client

import CollabClient from '@pdftron/collab-client';
const client = new CollabClient({
...options
});
const submitButton = document.getElementById('loginButton');
// set up an onclick handler for your login form
submitButton.onClick = async () => {
const email = document.getElementById('emailField').value;
const password = document.getElementById('passwordField').value;
try {
const { user } = await client.loginWithPassword(email, password);
// user logged in!
} catch (e) {
// error occurred, probably invalid credentials
}
};