The State of Docs Report 2025 is live! Dive in and see why docs matter more than ever:
Read the report
LogoLogo
Product
HomepageBook a demoCommunityBlog
PricingLog inSign up

Product
HomepageBook a demoCommunityBlogPricingLog inSign up
  • Documentation
  • Developers
  • Guides
  • Changelog
  • Help Center
  • Getting Started
    • GitBook Documentation
    • Quickstart
    • Importing content
    • GitHub & GitLab Sync
      • Enabling GitHub Sync
      • Enabling GitLab Sync
      • Content configuration
      • GitHub pull request preview
      • Commit messages & Autolink
      • Monorepos
      • Troubleshooting
  • Creating Content
    • Formatting your content
      • Inline content
      • Markdown
    • Content structure
      • Spaces
      • Pages
      • Collections
    • Blocks
      • Paragraphs
      • Headings
      • Unordered lists
      • Ordered lists
      • Task lists
      • Hints
      • Quotes
      • Code blocks
      • Files
      • Images
      • Embedded URLs
      • Tables
      • Cards
      • Tabs
      • Expandable
      • Stepper
      • Drawings
      • Math & TeX
      • Page links
    • Reusable content
    • Broken links
    • Searching content
      • Search & Quick find
      • GitBook AI
    • Writing with GitBook AI
    • Version control
  • API References
    • OpenAPI
      • Add an OpenAPI specification
      • Insert API reference in your docs
    • Guides
      • Structuring your API reference
      • Adding custom code samples
      • Managing API operations
      • Describing enums
      • Integrating with CI/CD
  • Extensions reference
  • Publishing Documentation
    • Publish a docs site
      • Public publishing
      • Private publishing with share links
    • Site structure
      • Content variants
      • Site sections
    • Site customization
      • Icons, colors, and themes
      • Layout and structure
      • Extra configuration
    • Set a custom domain
    • Setting a custom subdirectory
      • Configuring a subdirectory with Cloudflare
      • Configuring a subdirectory with Vercel
    • Site settings
    • Site insights
    • Site redirects
    • Visitor authentication
      • Enabling visitor authentication
      • Setting up Auth0
      • Setting up Azure AD
      • Setting up AWS Cognito
      • Setting up Okta
      • Setting up OIDC
      • Setting up a custom backend
  • LLM-ready docs
  • Collaboration
    • Live edits
    • Change requests
    • PDF export
    • Inviting your team
    • Comments
    • Notifications
  • Integrations
    • Install and manage integrations
    • GitHub Copilot
  • Account management
    • Plans
      • Legacy pricing
      • Sponsored site plan
      • Non-profit plan
      • Billing policy
    • Subscription cancellations
    • Personal settings
    • Organization settings
    • Member management
      • Invite or remove members
      • Roles
      • Teams
      • Permissions and inheritance
    • SSO & SAML
      • SSO Members vs non-SSO
  • Resources
    • GitBook UI
    • Keyboard shortcuts
    • Glossary
Powered by GitBook
On this page
  • Overview
  • 1. Create a custom backend to authenticate your users
  • 2. Sign and pass a JWT token to GitBook
  • 3. Configure a fallback URL
  • 4. Set up multi-tenant Visitor Authentication (optional)
  • 5. Configure your backend for adaptive content (optional)

Was this helpful?

Edit on GitHub
  1. Publishing Documentation
  2. Visitor authentication

Setting up a custom backend

Set up an custom login screen for visitors to your docs.

Last updated 28 days ago

Was this helpful?

LogoLogo

Resources

  • Showcase
  • Enterprise
  • Status

Company

  • Careers
  • Blog
  • Community

Policies

  • Subprocessors
  • Terms of Service

This guide takes your through setting up a protected sign-in screen for your docs. Before going through this guide, make sure you’ve first gone through “”.

This guide walks you through setting up a protected sign-in screen for your GitBook documentation site using your own custom authentication backend.

If you are using one of the authentication providers we support or have an (OIDC) compliant backend, check out our integration guides for a more streamlined setup: | | | |

Overview

To setup a custom authentication system for your GitBook site, follow these key steps:

1

Implement a backend that prompts users to login and authenticate them.

2

Create a JWT token and sign it with your site’s private key.

3

Configure a URL to be used when an unauthenticated visitor access your site.

4

Configure your backend to handle authentication across multiple GitBook sites.

5

Configure your backend to work with adaptive content in GitBook.

1. Create a custom backend to authenticate your users

In order to start authenticating users before they can visit your documentation, you’ll need to set up a server that can handle login and authentication of users.

Your backend should:

  • Prompt users to log in using your preferred authentication method.

  • Validate user credentials and authenticate them.

  • Generate and sign a JSON Web Token (JWT) upon successful authentication.

  • Redirect users to GitBook with the JWT included in the URL.

2. Sign and pass a JWT token to GitBook

Once your backend authenticates a user, it must generate a JWT and pass it to GitBook when redirecting them to your site. The token should be signed using the private key provided in your site's audience settings after .

The following example should demonstrate how a login request handler in your custom backend could look like:

index.ts
import { Request, Response } from 'express';
import * as jose from 'jose';

import { getUserInfo } from '../services/user-info-service';
import { getFeatureFlags } from '../services/feature-flags-service';

const GITBOOK_VISITOR_SIGNING_KEY = process.env.GITBOOK_VISITOR_SIGNING_KEY!;
const GITBOOK_DOCS_URL = 'https://mycompany.gitbook.io/myspace';

export async function handleAppLoginRequest(req: Request, res: Response) {
    // Your business logic for handling the login request
    // For example, checking credentials and authenticating the user
    //
    // e.g.:
    // const loggedInUser = await authenticateUser(req.body.username, req.body.password);
    
    // Generate a signed JWT
    const gitbookVisitorJWT = await new jose.SignJWT({})
        .setProtectedHeader({ alg: 'HS256' })
        .setIssuedAt()
        .setExpirationTime('2h') // Arbitrary 2-hour expiration
        .sign(new TextEncoder().encode(GITBOOK_VISITOR_SIGNING_KEY));
    
    // Redirect the user to GitBook with the JWT token in the URL
    const redirectURL = `${GITBOOK_DOCS_URL}/?jwt_token=${gitbookVisitorJWT}`;
    res.redirect(redirectURL);
}

3. Configure a fallback URL

The fallback URL is used when an unauthenticated visitor tries to access your protected site. GitBook will then redirect them to this URL.

This URL should point to a handler in your custom backend, where you can prompt them to login, authenticate and then redirect them back to your site with the JWT included in the URL.

For instance, if your login screen is located at https://example.com/login, you should include this value as the fallback URL.

You can configure this fallback URL within your site's audience settings under the “Visitor authentication” tab.

When redirecting to the fallback URL, GitBook includes a location query parameter to the fallback URL that you can leverage in your handler to redirect the user to the original location of the user:

const gitbookVisitorJWT = await new jose.SignJWT({})
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime('2h') // Arbitrary 2-hour expiration
    .sign(new TextEncoder().encode(GITBOOK_VISITOR_SIGNING_KEY));
    
// Redirect to the original GitBook docs URL with the JWT included as jwt_token query parameter
// If a location is provided, the user will be redirected back to their original destination
const redirectURL = `${GITBOOK_DOCS_URL}/${req.query.location || ''}?jwt_token=${gitbookVisitorJWT}`;
res.redirect(redirectURL);

4. Set up multi-tenant Visitor Authentication (optional)

If you're using GitBook as a platform to provide content to your different customers, you probably need to set up multi-tenant visitor authentication. Your authentication backend needs to be responsible for handling authentication across multiple different sites. This is possible in GitBook with a few small tweaks to your custom authentication backend code.

Adding all tenants to your authentication server

Your authentication backend will need to know the JWT signing keys and the URLs of all the GitBook sites you expect it to handle. If you have two sites in your organization for Customer A and Customer B, you can imagine your authentication code storing such mapping:

const CUSTOMER_A = {
  jwtSigningKey: 'aaa-aaa-aaa-aaa',
  url: 'https://mycompany.gitbook.io/customer-a'
};

const CUSTOMER_B = {
  jwtSigningKey: 'bbb-bbb-bbb-bbb',
  url: 'https://mycompany.gitbook.io/customer-b'
};

Giving your authentication server additional context

When GitBook is unable to authenticate a user's request, it redirects them to the fallback URL. This URL points to your authentication backend, which is responsible for authenticating the user and redirecting them back to the requested content.

To support multiple tenants, your authentication backend needs to know which GitBook site the user is meant to access. This information can be passed in the fallback URL.

So for example, you could setup the fallback URLs for each sites as follow:

GitBook Site
Fallback URL

Customer A site

https://auth-backend.acme.org/login?site=customer-a

Customer B site

https://auth-backend.acme.org/login?site=customer-b

Your authentication backend can then check this information and handle the redirection to the correct site accordingly:

const customerInfo = req.query.site === 'customer-a' ? CUSTOMER_A : CUSTOMER_B;
  
const gitbookVisitorJWT = await new jose.SignJWT({})
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime('2h') // Arbitrary 2-hour expiration
    .sign(new TextEncoder().encode(customerInfo.jwtSigningKey));
    
// Redirect to the original GitBook docs URL with the JWT included as jwt_token query parameter
// If a location is provided, the user will be redirected back to their original destination
const redirectURL = `${customerInfo.url}/${req.query.location || ''}?jwt_token=${gitbookVisitorJWT}`;
res.redirect(redirectURL);

5. Configure your backend for adaptive content (optional)

To leverage the Adaptive Content capability in your visitor authentication setup, you can include additional user attributes (claims) in the payload of the JWT that your custom backend generates and include in the URL when redirecting the user to the site.

These claims when included in the JWT are used by GitBook to adapt content dynamically for your site visitors.

Putting it all together, the following code example demonstrates how you could include these claims in the JWT, which can then be used by GitBook to adapt content for your visitors:

index.ts
import { Request, Response } from 'express';
import * as jose from 'jose';

import { getUserInfo } from '../services/user-info-service';
import { getFeatureFlags } from '../services/feature-flags-service';

const GITBOOK_VISITOR_SIGNING_KEY = process.env.GITBOOK_VISITOR_SIGNING_KEY!;
const GITBOOK_DOCS_URL = 'https://mycompany.gitbook.io/myspace';

export async function handleAppLoginRequest(req: Request, res: Response) {
    // Your business logic for handling the login request
    // For example, checking credentials and authenticating the user
    //
    // e.g.:
    // const loggedInUser = await authenticateUser(req.body.username, req.body.password);
    
    // For the purpose of this example, assume a logged-in user object
    const loggedInUser = { id: '12345' }; // Replace with actual authentication logic

    // Retrieve user information to pass to GitBook
    const userInfo = await getUserInfo(loggedInUser.id);
    
    // Generate a signed JWT and include the user attributes as claims
    const gitbookVisitorClaims = {
        firstName: userInfo.firstName,
        lastName: userInfo.lastName,
        isBetaUser: userInfo.isBetaUser,
        products: userInfo.products.map((product) => product.name),
        featureFlags: await getFeatureFlags({ userId: loggedInUser.id })
    };
    
    const gitbookVisitorJWT = await new jose.SignJWT(gitbookVisitorClaims)
        .setProtectedHeader({ alg: 'HS256' })
        .setIssuedAt()
        .setExpirationTime('2h') // Arbitrary 2-hour expiration
        .sign(new TextEncoder().encode(GITBOOK_VISITOR_SIGNING_KEY));
    
    // Redirect the user to GitBook with the JWT token in the URL
    const redirectURL = `${GITBOOK_DOCS_URL}/?jwt_token=${gitbookVisitorJWT}`;
    res.redirect(redirectURL);
}

After setting up and configuring the right claims to send to GitBook, head to “Adapting your content” to continue configuring your site.

Enabling visitor authentication
OpenID Connect
Auth0
Azure AD
Okta
AWS Cognito
OIDC
Create a custom backend to authenticate your users
Sign and pass a JWT token to GitBook
Configure a fallback URL
Set up multi-tenant Visitor Authentication (optional)
Configure your backend for adaptive content (optional)
enabling Visitor Authentication
Configure a fallback URL

This feature is still under development and coming soon.

Please sign up for the waitlist at

https://www.gitbook.com/