Files
mintlify__docs/deploy/authentication-setup.mdx
2026-02-07 17:44:27 +00:00

391 lines
14 KiB
Plaintext

---
title: "Authentication setup"
description: "Control access to your documentation by authenticating users."
keywords: ['authentication', 'auth', 'OAuth', 'JWT', 'password']
---
<Info>
[Pro plans](https://mintlify.com/pricing?ref=authentication) include password authentication.
[Enterprise plans](https://mintlify.com/pricing?ref=authentication) include all authentication methods.
</Info>
Authentication requires users to log in before accessing your documentation. You can configure specific pages or groups as public while keeping other pages protected.
## Configure authentication
<Tabs>
<Tab title="Password">
<Info>
Password authentication provides access control only and does **not** support user-specific features like group-based access control or API playground pre-filling.
</Info>
### Prerequisites
* Your security requirements allow sharing passwords among users.
### Set up
<Steps>
<Step title="Create a password.">
1. In your dashboard, go to [Authentication](https://dashboard.mintlify.com/products/authentication).
2. Enable authentication.
3. In the **Password Protection** section, enter a secure password
After you enter a password, your site redeploys. When it finishes deploying, anyone who visits your site must enter the password to access your content.
</Step>
<Step title="Distribute access.">
Securely share the password and documentation URL with authorized users.
</Step>
</Steps>
</Tab>
<Tab title="Mintlify dashboard">
### Prerequisites
* Everyone who needs to access your documentation must be a member of your Mintlify organization.
### Set up
<Steps>
<Step title="Enable Mintlify dashboard authentication.">
1. In your dashboard, go to [Authentication](https://dashboard.mintlify.com/products/authentication).
2. Enable authentication.
3. In the **Custom Authentication** section, click **Mintlify Auth**.
4. Click **Enable Mintlify Auth**.
After you enable Mintlify authentication, your site redeploys. When it finishes deploying, anyone who visits your site must log in to your Mintlify organization to access your content.
</Step>
<Step title="Add authorized users.">
1. In your dashboard, go to [Members](https://dashboard.mintlify.com/settings/organization/members).
2. Add each person who should have access to your documentation.
3. Assign appropriate roles based on their editing permissions.
</Step>
</Steps>
</Tab>
<Tab title="OAuth 2.0">
### Prerequisites
* An OAuth or OIDC server that supports the Authorization Code Flow.
* Ability to create an API endpoint accessible by OAuth access tokens (optional, to enable group-based access control).
### Set up
<Steps>
<Step title="Configure your OAuth settings.">
1. In your dashboard, go to [Authentication](https://dashboard.mintlify.com/products/authentication).
2. Enable authentication.
3. In the **Custom Authentication** section, click **OAuth**.
4. Configure these fields:
* **Authorization URL**: Your OAuth endpoint.
* **Client ID**: Your OAuth 2.0 client identifier.
* **Client Secret**: Your OAuth 2.0 client secret.
* **Scopes** (optional): Permissions to request.
* **Additional authorization parameters** (optional): Additional query parameters to add to the initial authorization request.
* **Token URL**: Your OAuth token exchange endpoint.
* **Info API URL** (optional): Endpoint on your server that Mintlify calls to retrieve user info. Required for group-based access control.
* **Logout URL** (optional): The native logout URL for your OAuth provider. If not configured, users redirect to `/login`.
* **Redirect URL** (optional): The URL to redirect users to after authentication.
5. Click **Save changes**.
After you configure your OAuth settings, your site redeploys. When it finishes deploying, anyone who visits your site must log in to your OAuth provider to access your content.
</Step>
<Step title="Configure your OAuth server.">
1. Copy the **Redirect URL** from your [authentication settings](https://dashboard.mintlify.com/products/authentication).
2. Add the redirect URL as an authorized redirect URL for your OAuth server.
</Step>
<Step title="Create your user info endpoint (optional).">
To enable group-based access control, create an API endpoint that:
* Responds to `GET` requests.
* Accepts an `Authorization: Bearer <access_token>` header for authentication.
* Returns user data in the `User` format. See [User data format](#user-data-format) for more information.
Mintlify calls this endpoint with the OAuth access token to retrieve user information.
Add this endpoint URL to the **Info API URL** field in your [authentication settings](https://dashboard.mintlify.com/products/authentication).
</Step>
</Steps>
<Note>
Control session length with the `expiresAt` field in your user info response. This is a Unix timestamp (seconds since epoch) indicating when the session should expire. See [User data format](#user-data-format) for more details.
</Note>
</Tab>
<Tab title="JWT">
### Prerequisites
* An authentication system that can generate and sign JWTs.
* A backend service that can create redirect URLs.
### Set up
<Steps>
<Step title="Generate a private key.">
1. In your dashboard, go to [Authentication](https://dashboard.mintlify.com/products/authentication).
2. Enable authentication.
3. In the **Custom Authentication** section, click **JWT**.
4. Enter the URL of your existing login flow.
5. Click **Save changes**.
6. Click **Generate new key**.
7. Store your key securely where it can be accessed by your backend.
After you generate a private key, your site redeploys. When it finishes deploying, anyone who visits your site must log in to your JWT authentication system to access your content.
</Step>
<Step title="Integrate Mintlify authentication into your login flow.">
Modify your existing login flow to include these steps after user authentication:
* Create a JWT containing the authenticated user's info in the `User` format. See [User data format](#user-data-format) 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.
</Step>
</Steps>
### Example
After verifying user credentials, generate a JWT with user data and redirect to `https://docs.foo.com/login/jwt-callback#{SIGNED_JWT}`.
<CodeGroup>
```ts TypeScript
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,
apiPlaygroundInputs: {
header: {
"Authorization": `Bearer ${res.locals.user.apiKey}`,
},
},
};
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}`);
}
```
```python Python
import jwt # pyjwt
import os
from datetime import datetime, timedelta
from fastapi.responses import RedirectResponse
private_key = os.getenv(MINTLIFY_JWT_PEM_SECRET_NAME, '')
@router.get('/auth')
async def return_mintlify_auth_status(current_user):
jwt_token = jwt.encode(
payload={
'exp': int((datetime.now() + timedelta(seconds=10)).timestamp()), # 10 second JWT expiration
'expiresAt': int((datetime.now() + timedelta(weeks=2)).timestamp()), # 2 week session expiration
'groups': ['admin'] if current_user.is_admin else [],
'apiPlaygroundInputs': {
'header': {
'Authorization': f'Bearer {current_user.api_key}',
},
},
},
key=private_key,
algorithm='EdDSA'
)
return RedirectResponse(url=f'https://docs.foo.com/login/jwt-callback#{jwt_token}', status_code=302)
```
</CodeGroup>
### Redirect unauthenticated users
When an unauthenticated user tries to access a protected page, the redirect to your login URL preserves the user's intended destination.
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.
</Tab>
</Tabs>
## Make pages public
When using authentication, all pages require authentication by default. You can make specific pages viewable without authentication at the page or group level with the `public` property.
### Individual pages
Add `public: true` to the page's frontmatter.
```mdx Public page example
---
title: "Public page"
public: true
---
```
### Groups of pages
Add `"public": true` beneath the group's name in the `navigation` object of your `docs.json`.
```json Public group example
{
"navigation": {
"groups": [
{
"group": "Public group",
"public": true,
"icon": "play",
"pages": [
"quickstart",
"installation",
"settings"
]
},
{
"group": "Private group",
"icon": "pause",
"pages": [
"private-information",
"secret-settings"
]
}
]
}
}
```
## Control access with groups
When you use OAuth or JWT authentication, you can restrict specific pages to certain user groups. Manage groups through user data passed during authentication. See [User data format](#user-data-format) for details.
```json Example user info
{
"groups": ["admin", "beta-users"],
"expiresAt": 1735689600
}
```
Specify which groups can access specific pages using the `groups` property in frontmatter.
```mdx Example page restricted to the admin group highlight={3}
---
title: "Admin dashboard"
groups: ["admin"]
---
```
Users must belong to at least one of the listed groups to access the page. If a user tries to access a page without the required group, they'll receive a 404 error.
### How groups interact with public pages
- All pages require authentication by default.
- Pages with a `groups` property are only accessible to authenticated users in those groups.
- Pages without a `groups` property are accessible to all authenticated users.
- Pages with `public: true` and no `groups` property are accessible to everyone.
<CodeGroup>
```mdx Public page
---
title: "Public guide"
public: true
---
```
```mdx Protected page
---
title: "API reference"
---
```
```mdx Protected page with groups
---
title: "Advanced configurations"
groups: ["pro", "enterprise"]
---
```
</CodeGroup>
## User data format
When using OAuth or JWT authentication, your system returns user data that controls session length, group membership, and [content personalization](/create/personalization).
<CodeGroup>
```tsx Format
type User = {
expiresAt?: number;
groups?: string[];
content?: Record<string, any>;
apiPlaygroundInputs?: {
server?: Record<string, string>;
header?: Record<string, unknown>;
query?: Record<string, unknown>;
cookie?: Record<string, unknown>;
};
};
```
```json Example
{
"expiresAt": 1735689600,
"groups": ["admin", "beta-users"],
"content": {
"firstName": "Jane",
"company": "Acme Corp"
},
"apiPlaygroundInputs": {
"header": {
"Authorization": "Bearer user_abc123"
},
"server": {
"baseUrl": "https://api.foo.com"
}
}
}
```
</CodeGroup>
<ParamField path="expiresAt" type="number">
Session expiration time in seconds since epoch. When the current time passes this value, the user must re-authenticate.
<Warning>**For JWT:** This differs from the JWT's `exp` claim, which determines when a JWT is considered invalid. Set the JWT `exp` claim to a short duration (10 seconds or less) for security. Use `expiresAt` for the actual session length (hours to weeks).</Warning>
</ParamField>
<ParamField path="groups" type="string[]">
List of groups the user belongs to. Pages with matching `groups` in their frontmatter are accessible to this user.
**Example**: A user with `groups: ["admin", "engineering"]` can access pages tagged with either the `admin` or `engineering` groups.
</ParamField>
<ParamField path="content" type="Record<string, any>">
Custom data accessible in MDX pages via the `user` variable for [personalized content](/create/personalization#dynamic-mdx-content).
</ParamField>
<ParamField path="apiPlaygroundInputs" type="object">
Pre-fills API playground fields with user-specific values. When a user authenticates, these values populate the corresponding input fields in the API playground. Users can override pre-filled values, and their overrides persist in local storage.
Only values that match the current endpoint's security scheme are applied.
<Expandable title="properties">
<ParamField path="header" type="Record<string, unknown>">
Header values to pre-fill, keyed by header name.
</ParamField>
<ParamField path="query" type="Record<string, unknown>">
Query parameter values to pre-fill, keyed by parameter name.
</ParamField>
<ParamField path="cookie" type="Record<string, unknown>">
Cookie values to pre-fill, keyed by cookie name.
</ParamField>
<ParamField path="server" type="Record<string, string>">
Server variable values to pre-fill, keyed by variable name.
</ParamField>
</Expandable>
</ParamField>