# Private docs

A docs site is public by default. You can make it private so that readers must sign in first, and limit single pages to some readers. This page covers the four access modes, page audiences, reader variables and read tokens for AI tools.

Access is set in the site's **Settings**, **Access**, which needs permission to manage the site (`docs:site:write`). Authors in the console are not affected: anyone whose organization role allows reading docs sees every draft and page there.

## Choose who can read

Under **Who can read the published site**, pick one:

| Mode | Who gets in |
| --- | --- |
| **Public** | Anyone with the link. Search engines index the site. |
| **Password** | Readers who enter one shared password. Good for a partner or an early-access group. |
| **EvoHub members** | People in your EvoHub organization, optionally only some teams or roles. |
| **Your own sign-in (JWT)** | Readers your own app signs in and sends to the site with a signed token. Pages can be personalised. |

Then choose **Save access settings**.

On any private site:

- The site is not indexed by search engines and has no sitemap.
- **Session lifetime** sets how long a reader stays signed in: 1 hour, 8 hours, 24 hours, 3 days, 7 days or 30 days.
- **Sign everyone out** ends every reader's session at once. Changing who can read, the teams or roles, or the JWT key also signs everyone out.
- Analytics and the "Was this page helpful?" widget keep working for signed-in readers.
- Uploaded files and images stay reachable by their address.
- Change request preview links keep working with their own token and show every page, so share them like a password.

Readers sign in on the site's own domain, so a private site needs an active custom domain. See [Connect a custom domain](https://docs-dev.evohub.io/docs-custom-domain.md).

## Password

Pick **Password**, then under **Site password** enter 8 to 128 characters and choose **Set password** (or **Change password**). The password is stored hashed and cannot be shown again. Changing it signs every reader out.

Repeated wrong passwords are slowed down: after too many attempts in a short time, sign-in is refused for a while.

## EvoHub members

Pick **EvoHub members**. By default every active member of your organization can read the site. Under **Who may read**, add **Teams** or **Roles** to narrow it down; a reader needs to be in one of them.

Readers sign in with their EvoHub account; the docs site never sees their EvoHub login. A sign-in lasts at most 12 hours, and every visit is checked against EvoHub, so people who are removed from the organization, suspended, signed out of EvoHub everywhere, or no longer in the listed teams or roles lose access within 30 seconds.

## Your own sign-in (JWT)

Use this when your readers already sign in to your own app. Your app signs a short-lived token for the reader and sends them to the docs site with it.

### Configure the key

Under **Verify tokens from your app**, pick the **Algorithm**:

- **HS256 (shared secret)** — **Generate a secret** (shown once; copy it now) or paste your own of 32 characters or more. A new secret signs everyone out.
- **RS256 (RSA public key)** or **ES256 (EC P-256 public key)** — paste the public key (RSA of 2048 bits or more, or EC P-256), or give a JWKS address (`https` only; keys are matched by `kid`). Never paste a private key.

Optionally set **Issuer (iss)** and **Audience (aud)**; they are checked when set. Set the **Login address** where unauthenticated readers are sent (with `?redirect=<page>`), and the **Logout address** readers land on after signing out of the docs.

### The token

- `exp` is required and at most 24 hours ahead. The token is a sign-in link, not a credential: keep it to minutes. `iat` may not be in the future.
- `groups` (a list of strings, or comma-separated text) decides which audience pages the reader sees.
- Every other string, number or boolean claim becomes a reader variable, such as `{{user.name}}` or `{{user.plan}}`. Up to 30 claims, 500 characters each.
- `jti`, when present, makes the token work only once.

Send the reader to `/_auth/jwt` on your docs domain with the token:

```js
import jwt from "jsonwebtoken";

// After your own login check, sign a short-lived token for this reader.
const token = jwt.sign(
  {
    sub: user.id,
    name: user.name,
    email: user.email,
    groups: ["customers"],
    plan: "pro",
  },
  process.env.DOCS_JWT_SECRET,
  { algorithm: "HS256", expiresIn: "10m" },
);

res.redirect(`https://docs.example.com/_auth/jwt?token=${token}&return=/`);
```

### Test it

Under **Try it**, **Make a test token** creates a token for the saved HS256 settings with the subject, name, email, groups and extra claims you enter, valid for up to 60 minutes. **Verify a token** checks a token your app signed and tells you whether a reader with it would be let in, or why not.

## Page audiences

On a private site that signs readers in with JWT or EvoHub members, you can limit a page to some readers. In the page settings, under **Audience**, add groups:

- with JWT, the `groups` in the reader's token;
- with EvoHub members, team ids and roles such as `org:admin` (the picker offers **Team:** and **Role:** entries).

Only readers in one of the groups see the page. For everyone else it does not exist: it is left out of the navigation, search, `llms.txt` and the MCP server, and its address answers "not found". The audience is a page setting, so it goes live when the page is published. In a GitHub repository, set it with the `audience` front matter key:

```yaml
---
title: Partner pricing
audience: [partners, org:admin]
---
```

> [!WARNING]
> On a public site, and for readers who sign in with the shared password, nobody belongs to a group — so a page with an audience is shown to no one.

## Reader variables

On JWT and EvoHub members sites, `{{user.name}}`, `{{user.email}}` and any other claim are replaced with the signed-in reader's details in the page text. They are left as written on public sites and in previews. See [Writing pages](https://docs-dev.evohub.io/writing-pages.md#reader-variables).

## Read tokens for AI tools

A private site is closed to AI assistants and scripts unless they send a token. Under **Read tokens for AI tools**, give a token a **Name** and, optionally, the groups it reads as, then **Create token**. Copy it when it is shown; it is not shown again.

The token reads the site — including its MCP server and the `.md` copies of pages — as a reader in those groups. Send it as `Authorization: Bearer <token>`. The console shows ready-made setup for Claude Code and for MCP configuration files. A site holds up to 10 tokens; revoke one at any time.

## Related

- [Connect a custom domain](https://docs-dev.evohub.io/docs-custom-domain.md)
- [API references and AI](https://docs-dev.evohub.io/api-references-and-ai.md)
- [Writing pages](https://docs-dev.evohub.io/writing-pages.md)
