Control access to your documentation by authenticating individual users.
Authentication methods are available on Growth and Enterprise plans.

Choose your method

Use JWT if:
  • You want full control over the login flow and user data.
  • You need custom authentication logic.
  • You prefer to manage tokens yourself.
Use OAuth 2.0 if:
  • You want to integrate with third-party providers (Google, GitHub, etc.).
  • You want to leverage existing OAuth infrastructure.
  • You prefer standardized security protocols.
Use the Mintlify dashboard if:
  • Your editors are also your documentation users.
  • You want a zero configuration setup.

Configuration

Select the method that you want to configure. TODO: verify steps with new UI

Prerequisites

  • An authentication system that can generate and sign JWTs.
  • A backend service that can create redirect URLs.

Implementation

1

Generate a private key.

  1. In your dashboard, go to Protected pages.
  2. Select JWT.
  3. Enter the URL of your existing login flow and select Save changes.
  4. Select Generate new key.
  5. Store your key securely where it can be accessed by your backend.
2

Integrate Mintlify authentication into your login flow.

Modify your existing login flow to include these steps after user authentication:
  • TODO: what format is needed? Create a JWT containing the authenticated user’s info in the User format. See Sending Data for more information.
  • Sign the JWT with your secret key, using the EdDSA algorithm.
  • Create a redirect URL back to the /login/jwt-callback path of your docs, including the JWT as the hash.

Example

Your documentation is hosted at docs.foo.com with an existing authentication system at foo.com. You want to extend your login flow to grant access to the docs while keeping your docs separate from your dashboard.Create a login endpoint at https://foo.com/docs-login that extends your existing authentication.After verifying user credentials:
  • Generate a JWT with user data in Mintlify’s format.
  • Sign the JWT and redirect to https://docs.foo.com/login/jwt-callback#{SIGNED_JWT}.
import * as jose from 'jose';
import { Request, Response } from 'express';

const TWO_WEEKS_IN_MS = 1000 * 60 * 60 * 24 * 7 * 2;

const signingKey = await jose.importPKCS8(process.env.MINTLIFY_PRIVATE_KEY, 'EdDSA');

export async function handleRequest(req: Request, res: Response) {
  const user = {
    expiresAt: Math.floor((Date.now() + TWO_WEEKS_IN_MS) / 1000), // 2 week session expiration
    groups: res.locals.user.groups,
    content: {
      firstName: res.locals.user.firstName,
      lastName: res.locals.user.lastName,
    },
  };

  const jwt = await new jose.SignJWT(user)
    .setProtectedHeader({ alg: 'EdDSA' })
    .setExpirationTime('10 s') // 10 second JWT expiration
    .sign(signingKey);

  return res.redirect(`https://docs.foo.com/login/jwt-callback#${jwt}`);
}

Redirecting unauthenticated users

When an unauthenticated user tries to access a protected page, their intended destination is preserved in the redirect to your login URL:
  1. User attempts to visit a protected page: https://docs.foo.com/quickstart.
  2. Redirect to your login URL with a redirect query parameter: https://foo.com/docs-login?redirect=%2Fquickstart.
  3. After authentication, redirect to https://docs.foo.com/login/jwt-callback?redirect=%2Fquickstart#{SIGNED_JWT}.
  4. User lands in their original destination.