Emovart Docs
Protected Access

How To Set Up Custom Backend Authentication For Your Emovart Site

Plug your own login system into Emovart: your server signs a token for each authenticated user, and only requests carrying a valid token can read your docs.

Last updated on July 9, 2026

🧠 Overview

Password and email list protection are managed for you by Emovart. Custom backend authentication hands the keys to your own server instead — the right choice when your readers already have accounts in your product, your intranet, or your SSO provider.

The flow looks like this:

  1. A visitor opens your protected site without a valid token.
  2. Emovart redirects them to the login URL you configured.
  3. Your backend authenticates them however it likes — existing session, database check, SSO.
  4. Your backend signs a token (an HMAC-signed JWT containing the user's email and an expiry) with your site's signing secret, then redirects back to your docs with ?token=<jwt> appended.
  5. Emovart verifies the signature and expiry, starts a session, and serves the content.

Your secret never leaves your server, and Emovart never sees your users' credentials — only the signed proof that your backend vouched for them.

🔧 Configuring custom backend auth in the Emovart console

1. Open the Protected Access tab

Open Settings → Help Centers on emovart.studio, select your site, and switch to the Protected Access tab. Pick Custom backend as the access mode.

Protected Access tab
Protected Access tab

2. Enter your login URL

This is the page unauthenticated visitors get sent to — typically the login route of your own application, like https://app.example.com/docs-login.

Login URL field
Login URL field

Emovart appends a returnTo query parameter to this URL so you can bounce people back to the exact article they were trying to read — more on that below.

Saved custom auth settings
Saved custom auth settings

3. Generate and copy your signing secret

Click Generate secret and copy the value into your server's environment. This is the HMAC key your backend uses to sign tokens — treat it like a password and never ship it to the browser.

# on YOUR server only — never expose this in frontend code
EMOVART_SIGNING_SECRET=ks_live_5f9c2e7a41d8b06c3aa917f4e2d5c8b1

Once your backend signs tokens with it, an authenticated request to your docs simply looks like this:

https://docs.example.com/?token=eyJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6...

4. (Optional) Auto-redirect visitors

By default, locked-out visitors see a screen with a Log in button pointing at your login URL. Enable Auto redirect to skip that screen and forward them straight to your login page — the smoother choice when every reader is supposed to have an account with you.

5. Save and test

Save the settings, then open your site in a private browser window. You should land on your own login page; after signing in, you should be redirected back with a token and see your docs.

Redirect to custom login
Redirect to custom login
Authenticated docs view
Authenticated docs view

🛠️ Step-by-step implementation (Node.js example)

📂
The snippets below add up to one complete, minimal Express app. Copy them into an empty folder and you can run the entire login flow on localhost before wiring it into your real backend.

1. Environment variables (.env)

You need exactly two values: the signing secret from the console and the URL of your Emovart site (used as the fallback redirect target).

Configuration

# .env
EMOVART_SIGNING_SECRET=paste-the-secret-from-the-console
EMOVART_SITE_URL=https://your-slug.emovart.studio
PORT=3000
// config.js
require("dotenv").config();

module.exports = {
  secret: process.env.EMOVART_SIGNING_SECRET,
  siteUrl: process.env.EMOVART_SITE_URL,
  port: process.env.PORT || 3000,
};

2. Install dependencies

npm install express jsonwebtoken dotenv ejs
# or, if you prefer pnpm
pnpm add express jsonwebtoken dotenv ejs

3. Backend server code

The server needs two routes: one that shows the login form, and one that checks credentials and mints the token.

// server.js — setup and the login form route
const express = require("express");
const jwt = require("jsonwebtoken");
const { secret, siteUrl, port } = require("./config");

const app = express();
app.set("view engine", "ejs");
app.use(express.urlencoded({ extended: true }));

// Emovart sends visitors here with ?returnTo=<page they wanted>
app.get("/docs-login", (req, res) => {
  res.render("login", { returnTo: req.query.returnTo || "" });
});
// server.js — verify the user, sign the token, redirect back
app.post("/docs-login", (req, res) => {
  const { email, password, returnTo } = req.body;

  if (!isValidUser(email, password)) {
    return res.status(401).send("Invalid credentials");
  }

  const token = jwt.sign({ email }, secret, { expiresIn: "7d" });
  const base = returnTo || siteUrl;
  const sep = base.includes("?") ? "&" : "?";
  res.redirect(`${base}${sep}token=${token}`);
});

app.listen(port, () => console.log(`Login server on :${port}`));

4. Login form (EJS)

The form itself is deliberately boring: an email field, a password field, and a hidden returnTo input that carries the original destination through the POST. Save it as views/login.ejs and style it to match your product — this page is part of your app, so your users should feel at home on it.

🧪 Demo credentials (for local testing)

For a local dry run, stub the user check with hardcoded credentials:

// replace with your real user store before going live
function isValidUser(email, password) {
  return email === "demo@example.com" && password === "emovart-demo";
}
node server.js
# open http://localhost:3000/docs-login and sign in with
#   demo@example.com / emovart-demo

🔐 The JWT: payload and expiration

The token is a standard JWT signed with HS256 — an HMAC of the payload computed with your signing secret. Emovart requires a single claim, email; the iat and exp timestamps are added automatically by the library.

Example payload

{
  "email": "jane@example.com",
  "iat": 1767225600,
  "exp": 1767830400
}
const token = jwt.sign({ email: "jane@example.com" }, secret, {
  expiresIn: "7d",
});

Token expiration

Pick a lifetime that matches how long a login should last — your app's own session length is a sensible default:

jwt.sign({ email }, secret, { expiresIn: "12h" }); // tight, for sensitive docs
jwt.sign({ email }, secret, { expiresIn: "30d" }); // relaxed, for customer docs
// Expired or tampered tokens fail verification on Emovart's side,
// and the visitor is simply sent to your login URL again.
jwt.verify(token, secret); // throws TokenExpiredError once exp has passed

When a token expires, nothing dramatic happens: the reader lands back on your login page, and if they still have a session with your app you can immediately mint a fresh token and bounce them onward — they'll barely notice.

🔁 Redirection handling

Deep links matter in documentation — people arrive from support replies, bookmarks, and search results, not just the home page. Emovart therefore tells your login page exactly where the visitor was headed, and it's your job to carry that information through the login and honor it afterwards.

The returnTo parameter

When redirecting to your login URL, Emovart appends the full URL of the requested page:

https://app.example.com/docs-login?returnTo=https%3A%2F%2Fdocs.example.com%2Fhelp-center%2Fbilling%2Fchange-plan

After a successful login, redirect to returnTo — falling back to your site's home page — with the token attached:

const base = returnTo || siteUrl;
const sep = base.includes("?") ? "&" : "?";
res.redirect(`${base}${sep}token=${token}`);

🌍 Works with any backend

Nothing here is Node-specific. Any stack that can sign an HS256 JWT can protect a Emovart site: PyJWT for Python and Django, the jwt gem for Ruby and Rails, firebase/php-jwt for PHP and Laravel, golang-jwt for Go, or your framework's built-in JWT support. The recipe is always the same three steps: authenticate the user, sign { email } with your secret and an expiry, redirect back with ?token=.

🔗 Useful links

Need more help? If you get stuck wiring this up, reach out through the contact form in the console and we'll take a look at your setup together.

Was this article helpful?