From 940e3e667b73fa0fa5514d8937ef80a69409d7d2 Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 14:39:10 -0700 Subject: [PATCH 01/14] hide overview --- docs.json | 1 - 1 file changed, 1 deletion(-) diff --git a/docs.json b/docs.json index 2ad145a3d..77488a99b 100644 --- a/docs.json +++ b/docs.json @@ -115,7 +115,6 @@ { "group": "Authentication and personalization", "pages": [ - "authentication-personalization/overview", "authentication-personalization/authentication-setup", "authentication-personalization/partial-authentication-setup", "authentication-personalization/personalization-setup", From 8acdd6b78666daad72d8b66281d2da5fdf335ed7 Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 14:42:16 -0700 Subject: [PATCH 02/14] reorder auth methods --- .../authentication-setup.mdx | 230 +++++++++--------- 1 file changed, 115 insertions(+), 115 deletions(-) diff --git a/authentication-personalization/authentication-setup.mdx b/authentication-personalization/authentication-setup.mdx index 9e86c4aea..ba1e6a1cc 100644 --- a/authentication-personalization/authentication-setup.mdx +++ b/authentication-personalization/authentication-setup.mdx @@ -19,107 +19,64 @@ Authentication requires users to log in before accessing your documentation. Thi Select the handshake method that you want to configure. - + + +Password authentication provides access control only and does **not** support content personalization. + + ### Prerequisites -* An authentication system that can generate and sign JWTs. -* A backend service that can create redirect URLs. +* Your security requirements allow sharing passwords among users. ### Implementation - + 1. In your dashboard, go to [Authentication](https://dashboard.mintlify.com/settings/deployment/authentication). 2. Select **Full Authentication** or **Partial Authentication**. - 3. Select **JWT**. - 4. Enter the URL of your existing login flow and select **Save changes**. - 5. Select **Generate new key**. - 6. Store your key securely where it can be accessed by your backend. + 3. Select **Password**. + 4. Enter a secure password. + 5. Select **Save changes**. - - 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 [Sending Data](/authentication-personalization/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. + + Securely share the password and documentation URL with authorized users. -### 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 (or you don't have a 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}`. - - -```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, - 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); +## Example - return res.redirect(`https://docs.foo.com/login/jwt-callback#${jwt}`); -} -``` +Your documentation is hosted at `docs.foo.com` and you need basic access control without tracking individual users. You want to prevent public access while keeping setup simple. -```python Python -import jwt # pyjwt -import os +**Create a strong password** in your dashboard. **Share credentials** with authorized users. That's it! + + +### Prerequisites -from datetime import datetime, timedelta -from fastapi.responses import RedirectResponse +* Your documentation users are also your documentation editors. -private_key = os.getenv(MINTLIFY_JWT_PEM_SECRET_NAME, '') +### Implementation -@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()), # 1 week session expiration - 'groups': ['admin'] if current_user.is_admin else [], - 'content': { - 'firstName': current_user.first_name, - 'lastName': current_user.last_name, - }, - }, - key=private_key, - algorithm='EdDSA' - ) + + + 1. In your dashboard, go to [Authentication](https://dashboard.mintlify.com/settings/deployment/authentication). + 2. Select **Full Authentication** or **Partial Authentication**. + 3. Select **Mintlify Auth**. + 4. Select **Enable Mintlify Auth**. + + + 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. + + - return RedirectResponse(url=f'https://docs.foo.com/login/jwt-callback#{jwt_token}', status_code=302) -``` - +### Example -### Redirecting unauthenticated users +Your documentation is hosted at `docs.foo.com` and your team uses the dashboard to edit your docs. You want to restrict access to team members only. -When an unauthenticated user tries to access a protected page, their intended destination is preserved in the redirect to your login URL: +**Enable Mintlify authentication** in your dashboard settings. -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. +**Verify team access** by checking that all team members are added to your organization. ### Prerequisites @@ -180,63 +137,106 @@ Your documentation is hosted at `foo.com/docs` and you have an existing OAuth se **Configure your OAuth server to allow redirects** to your callback URL. - + ### Prerequisites -* Your documentation users are also your documentation editors. +* An authentication system that can generate and sign JWTs. +* A backend service that can create redirect URLs. ### Implementation - + 1. In your dashboard, go to [Authentication](https://dashboard.mintlify.com/settings/deployment/authentication). 2. Select **Full Authentication** or **Partial Authentication**. - 3. Select **Mintlify Auth**. - 4. Select **Enable Mintlify Auth**. + 3. Select **JWT**. + 4. Enter the URL of your existing login flow and select **Save changes**. + 5. Select **Generate new key**. + 6. Store your key securely where it can be accessed by your backend. - - 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. + + 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 [Sending Data](/authentication-personalization/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` and your team uses the dashboard to edit your docs. You want to restrict access to team members only. +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 (or you don't have a dashboard). -**Enable Mintlify authentication** in your dashboard settings. +Create a login endpoint at `https://foo.com/docs-login` that extends your existing authentication. -**Verify team access** by checking that all team members are added to your organization. - - - -Password authentication provides access control only and does **not** support content personalization. - +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}`. -### Prerequisites + +```ts TypeScript +import * as jose from 'jose'; +import { Request, Response } from 'express'; -* Your security requirements allow sharing passwords among users. +const TWO_WEEKS_IN_MS = 1000 * 60 * 60 * 24 * 7 * 2; -### Implementation +const signingKey = await jose.importPKCS8(process.env.MINTLIFY_PRIVATE_KEY, 'EdDSA'); - - - 1. In your dashboard, go to [Authentication](https://dashboard.mintlify.com/settings/deployment/authentication). - 2. Select **Full Authentication** or **Partial Authentication**. - 3. Select **Password**. - 4. Enter a secure password. - 5. Select **Save changes**. - - - Securely share the password and documentation URL with authorized users. - - +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, + }, + }; -## Example + const jwt = await new jose.SignJWT(user) + .setProtectedHeader({ alg: 'EdDSA' }) + .setExpirationTime('10 s') // 10 second JWT expiration + .sign(signingKey); -Your documentation is hosted at `docs.foo.com` and you need basic access control without tracking individual users. You want to prevent public access while keeping setup simple. + return res.redirect(`https://docs.foo.com/login/jwt-callback#${jwt}`); +} +``` -**Create a strong password** in your dashboard. **Share credentials** with authorized users. That's it! +```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()), # 1 week session expiration + 'groups': ['admin'] if current_user.is_admin else [], + 'content': { + 'firstName': current_user.first_name, + 'lastName': current_user.last_name, + }, + }, + key=private_key, + algorithm='EdDSA' + ) + + return RedirectResponse(url=f'https://docs.foo.com/login/jwt-callback#{jwt_token}', status_code=302) +``` + + +### 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. From 311bc2a1e9e025039bf34d0e8d1429fe1830ffb0 Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:07:49 -0700 Subject: [PATCH 03/14] combine partial and full auth --- .../authentication-setup.mdx | 63 +++++++++++++++++-- .../partial-authentication-setup.mdx | 25 -------- 2 files changed, 59 insertions(+), 29 deletions(-) delete mode 100644 authentication-personalization/partial-authentication-setup.mdx diff --git a/authentication-personalization/authentication-setup.mdx b/authentication-personalization/authentication-setup.mdx index ba1e6a1cc..667de5b23 100644 --- a/authentication-personalization/authentication-setup.mdx +++ b/authentication-personalization/authentication-setup.mdx @@ -1,12 +1,9 @@ --- title: "Authentication setup" -description: "Guarantee privacy of your docs by authenticating users" +description: "Control the privacy of your docs by authenticating users" icon: "file-lock" keywords: ['auth'] --- -Authentication requires users to log in before accessing your documentation. This guide covers setup for each available handshake method. - -**Need help choosing?** See the [overview](/authentication-personalization/overview) to compare options. [Pro plans](https://mintlify.com/pricing?ref=authentication) include password authentication. @@ -14,6 +11,18 @@ Authentication requires users to log in before accessing your documentation. Thi [Enterprise plans](https://mintlify.com/pricing?ref=authentication) include all authentication methods. +Authentication requires users to log in before accessing your documentation. + +## Authentication modes + +Choose between full and partial authentication modes based on your access control needs. + +**Full authentication**: All pages are protected. Users must log in before accessing any content. + +**Partial authentication**: Some pages are publicly viewable while others require authentication. Users can browse public content freely and authenticate only when accessing protected pages. + +When configuring any handshake method below, you'll select either **Full authentication** or **Partial authentication** in your dashboard settings. + ## Configuring authentication Select the handshake method that you want to configure. @@ -240,3 +249,49 @@ When an unauthenticated user tries to access a protected page, their intended de 4. User lands in their original destination. + +## Making pages public + +When using partial authentication, all pages are protected by default. You can make specific pages viewable without authentication at the page or group level with the `public` property. + +### Page level + +To make a page public, add `public: true` to the page's frontmatter. + +```mdx Public page example +--- +title: "Public page" +public: true +--- +``` + +### Group level + +To make all pages in a group public, 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" + ] + } + ] + } +} +``` \ No newline at end of file diff --git a/authentication-personalization/partial-authentication-setup.mdx b/authentication-personalization/partial-authentication-setup.mdx deleted file mode 100644 index f3b0e384a..000000000 --- a/authentication-personalization/partial-authentication-setup.mdx +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "Partial authentication setup" -description: "Control access to specific pages" -icon: "file-lock-2" -keywords: ["auth"] ---- - -Partial authentication lets you protect private documentation while keeping other pages publicly viewable. Users can browse public content freely and authenticate only when accessing protected pages. - -Partial authentication shares all the same features as authentication, but with the ability to allow unauthenticated users to view certain pages. - -## Setup - -Follow the [Authentication Setup](/authentication-personalization/authentication-setup) guide and select **Partial Authentication** when configuring your chosen handshake method. - -## Making pages public - -By default, all pages are protected. Add the `public` property to the page's frontmatter to make it viewable without authentication: - -```mdx ---- -title: "My Page" -public: true ---- -``` From 2196da85e6ec8947937db7950a468e160af73eb2 Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:08:46 -0700 Subject: [PATCH 04/14] format JSON example --- authentication-personalization/authentication-setup.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/authentication-personalization/authentication-setup.mdx b/authentication-personalization/authentication-setup.mdx index 667de5b23..944a08b16 100644 --- a/authentication-personalization/authentication-setup.mdx +++ b/authentication-personalization/authentication-setup.mdx @@ -275,8 +275,8 @@ To make all pages in a group public, add `"public": true` beneath the group's na "groups": [ { "group": "Public group", - "public": true, - "icon": "play", + "public": true, + "icon": "play", "pages": [ "quickstart", "installation", @@ -285,7 +285,7 @@ To make all pages in a group public, add `"public": true` beneath the group's na }, { "group": "Private group", - "icon": "pause", + "icon": "pause", "pages": [ "private-information", "secret-settings" From bf78486876184d326f660721d35ac32c888a0d57 Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:27:03 -0700 Subject: [PATCH 05/14] move Sending data into Personalization --- .../personalization-setup.mdx | 103 +++++++++++++++++- .../sending-data.mdx | 100 ----------------- 2 files changed, 98 insertions(+), 105 deletions(-) delete mode 100644 authentication-personalization/sending-data.mdx diff --git a/authentication-personalization/personalization-setup.mdx b/authentication-personalization/personalization-setup.mdx index 4f8d0e901..6157b3f78 100644 --- a/authentication-personalization/personalization-setup.mdx +++ b/authentication-personalization/personalization-setup.mdx @@ -4,9 +4,102 @@ description: "Let users log in for customized documentation experiences" icon: "user-cog" --- -Personalization lets you customize your documentation based on user information. This guide covers setup for each available handshake method. +Customize your documentation based on user information, including prefilling API playground inputs and adding dynamic content. + +## User data format + +When implementing personalization, your system returns user data in a specific format that enables content customization. This data can be sent as either a raw JSON object or within a signed JWT, depending on your handshake method. The shape of the data is the same for both. + +```tsx +type User = { + expiresAt?: number; + groups?: string[]; + content?: Record; + apiPlaygroundInputs?: { + header?: Record; + query?: Record; + cookie?: Record; + server?: Record; + }; +}; +``` + + + Session expiration time in **seconds since epoch**. If the user loads a page after this time, their stored data is automatically deleted and they must reauthenticate. + For JWT handshakes: 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). + + + A list of groups that the user belongs to. Pages with a matching `groups` field in their metadata will be visible to this user. + + **Example**: User with `groups: ["admin", "engineering"]` can access pages tagged with either the `admin` or `engineering` groups. + + + Custom data accessible in your `MDX` content via the `user` variable. Use this for dynamic personalization throughout your documentation. + + **Example**: + ```json + { "firstName": "Ronan", "company": "Acme Corp", "plan": "Enterprise" } + ``` + + **Usage in `MDX`**: + ```mdx + Welcome back, {user.firstName}! Your {user.plan} plan includes... + ``` + With the example `user` data, this would render as: Welcome back, Ronan! Your Enterprise plan includes... + + + User-specific values that will be prefilled in the API playground if supplied. Save users time when testing your APIs with their own data. + + **Example**: + ```json + { + "header": { "X-API-Key": "user_api_key_123" }, + "server": { "subdomain": "foo" }, + "query": { "org_id": "12345" } + } + ``` + If a user makes requests at a specific subdomain, you can send `{ server: { subdomain: 'foo' } }` as an `apiPlaygroundInputs` field. This value will be prefilled on any API page with the `subdomain` value. + + The `header`, `query`, and `cookie` fields will only prefill if they are part of your [OpenAPI security scheme](https://swagger.io/docs/specification/authentication/). If a field is in either the `Authorization` or `Server` sections, it will prefill. Creating a standard header parameter named `Authorization` will not enable this feature. + + +### Example user data -**Need help choosing?** See the [overview](/authentication-personalization/overview) to compare options. +```json +{ + "expiresAt": 1735689600, + "groups": ["admin", "beta-users"], + "content": { + "firstName": "Jane", + "lastName": "Smith", + "company": "TechCorp", + "plan": "Enterprise", + "region": "us-west" + }, + "apiPlaygroundInputs": { + "header": { + "Authorization": "Bearer abc123", + "X-Org-ID": "techcorp" + }, + "server": { + "environment": "production", + "region": "us-west" + } + } +} +``` ## Configuring personalization @@ -33,7 +126,7 @@ Select the handshake method that you want to configure. Modify your existing login flow to include these steps after user login: - * Create a JWT containing the logged in user's info in the `User` format. See [Sending Data](/authentication-personalization/sending-data) for more information. + * Create a JWT containing the logged in user's info in the `User` format. See the [User data format](#user-data-format) section above for more information. * Sign the JWT with the secret key, using the ES256 algorithm. * Create a redirect URL back to your docs, including the JWT as the hash. @@ -95,7 +188,7 @@ To redirect users to specific sections after login, use this URL format: `https: Create an API endpoint that: * Accepts OAuth access tokens for authentication. - * Returns user data in the `User` format. See [Sending Data](/authentication-personalization/sending-data) for more information. + * Returns user data in the `User` format. See the [User data format](#user-data-format) section above for more information. * Defines the scopes for access. @@ -157,7 +250,7 @@ Your documentation is hosted at `foo.com/docs` and you have an existing OAuth se Create an API endpoint that: * Uses your existing session authentication to identify users - * Returns user data in the `User` format (see [Sending Data](/authentication-personalization/sending-data)) + * Returns user data in the `User` format (see the [User data format](#user-data-format) section above) * If the API domain and the docs domain **do not exactly match**: * Add the docs domain to your API's `Access-Control-Allow-Origin` header (must not be `*`). * Set your API's `Access-Control-Allow-Credentials` header to `true`. diff --git a/authentication-personalization/sending-data.mdx b/authentication-personalization/sending-data.mdx deleted file mode 100644 index 2323f0b17..000000000 --- a/authentication-personalization/sending-data.mdx +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: "Sending data" -description: "User data format for personalizing your documentation" -icon: "send" ---- - -When implementing authentication or personalization, your system returns user data in a specific format that enables content customization. This data can be sent as either a raw JSON object or within a signed JWT, depending on your handshake method. The shape of the data is the same for both. - -## User data format - -```tsx -type User = { - expiresAt?: number; - groups?: string[]; - content?: Record; - apiPlaygroundInputs?: { - header?: Record; - query?: Record; - cookie?: Record; - server?: Record; - }; -}; -``` - - - Session expiration time in **seconds since epoch**. If the user loads a page after this time, their stored data is automatically deleted and they must reauthenticate. - For JWT handshakes: 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). - - - A list of groups that the user belongs to. Pages with a matching `groups` field in their metadata will be visible to this user. - - **Example**: User with `groups: ["admin", "engineering"]` can access pages tagged with either the `admin` or `engineering` groups. - - - Custom data accessible in your `MDX` content via the `user` variable. Use this for dynamic personalization throughout your documentation. - - **Example**: - ```json - { "firstName": "Ronan", "company": "Acme Corp", "plan": "Enterprise" } - ``` - - **Usage in `MDX`**: - ```mdx - Welcome back, {user.firstName}! Your {user.plan} plan includes... - ``` - With the example `user` data, this would render as: Welcome back, Ronan! Your Enterprise plan includes... - - - User-specific values that will be prefilled in the API playground if supplied. Save users time when testing your APIs with their own data. - - **Example**: - ```json - { - "header": { "X-API-Key": "user_api_key_123" }, - "server": { "subdomain": "foo" }, - "query": { "org_id": "12345" } - } - ``` - If a user makes requests at a specific subdomain, you can send `{ server: { subdomain: 'foo' } }` as an `apiPlaygroundInputs` field. This value will be prefilled on any API page with the `subdomain` value. - - The `header`, `query`, and `cookie` fields will only prefill if they are part of your [OpenAPI security scheme](https://swagger.io/docs/specification/authentication/). If a field is in either the `Authorization` or `Server` sections, it will prefill. Creating a standard header parameter named `Authorization` will not enable this feature. - - -## Example user data - -```json -{ - "expiresAt": 1735689600, - "groups": ["admin", "beta-users"], - "content": { - "firstName": "Jane", - "lastName": "Smith", - "company": "TechCorp", - "plan": "Enterprise", - "region": "us-west" - }, - "apiPlaygroundInputs": { - "header": { - "Authorization": "Bearer abc123", - "X-Org-ID": "techcorp" - }, - "server": { - "environment": "production", - "region": "us-west" - } - } -} -``` From 6af63985e6ed3bdd13a01e30d4e1416f05a4287f Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 15:29:53 -0700 Subject: [PATCH 06/14] set up redirects --- docs.json | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs.json b/docs.json index 77488a99b..a8b8b7ff3 100644 --- a/docs.json +++ b/docs.json @@ -116,9 +116,7 @@ "group": "Authentication and personalization", "pages": [ "authentication-personalization/authentication-setup", - "authentication-personalization/partial-authentication-setup", - "authentication-personalization/personalization-setup", - "authentication-personalization/sending-data" + "authentication-personalization/personalization-setup" ] }, { @@ -456,11 +454,19 @@ }, { "source": "settings/authentication-personalization/partial-authentication", - "destination": "authentication-personalization/partial-authentication-setup" + "destination": "authentication-personalization/authentication-setup" }, { "source": "settings/authentication-personalization/sending-data", - "destination": "authentication-personalization/sending-data" + "destination": "authentication-personalization/personalization-setup" + }, + { + "source": "authentication-personalization/partial-authentication-setup", + "destination": "authentication-personalization/authentication-setup" + }, + { + "source": "authentication-personalization/sending-data", + "destination": "authentication-personalization/personalization-setup" }, { "source": "settings/authentication-personalization/authentication-setup/jwt", From ba4726350d57aaf327093cbb121bb2a2701fb9a8 Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 16:22:37 -0700 Subject: [PATCH 07/14] add more conceptual info to personalization --- .../personalization-setup.mdx | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/authentication-personalization/personalization-setup.mdx b/authentication-personalization/personalization-setup.mdx index 6157b3f78..1bddcb1d6 100644 --- a/authentication-personalization/personalization-setup.mdx +++ b/authentication-personalization/personalization-setup.mdx @@ -4,7 +4,65 @@ description: "Let users log in for customized documentation experiences" icon: "user-cog" --- -Customize your documentation based on user information, including prefilling API playground inputs and adding dynamic content. +Personalization customizes your documentation for each user when they are logged in. For example, you can prefill their API keys, show content specific to their plan or role, or hide sections they don't need access to. + +## Personalized content + +Personalization allows you to customize content with these features. + +### API key prefilling + +Automatically populate API playground fields with user-specific values by returning matching field names in your user data. The field names in your user data must exactly match the names in the API playground for automatic prefilling to work. + +### Dynamic MDX content + +Display dynamic content based on user information like name, plan, or organization. + +The `user` variable contains information sent to your docs from logged in users. See the [User data format](#user-data-format) section below for more information. + +**Example**: Hello, {user.name ?? 'reader'}! + +```jsx +Hello, {user.name ?? 'reader'}! +``` + +This feature is more powerful when you pair it with custom data about your users. For example, you can give different instructions based on a user's plan. + +**Example**: Authentication is an enterprise feature. { +user.org === undefined +? <>To access this feature, first create an account at the Mintlify dashboard. +: user.org.plan !== 'enterprise' +? <>You are currently on the ${user.org.plan ?? 'free'} plan. See our pricing page for information about upgrading. +: <>To request this feature for your enterprise org, contact your admin. +} + +```jsx +Authentication is an enterprise feature. { + user.org === undefined + ? <>To access this feature, first create an account at the Mintlify dashboard. + : user.org.plan !== 'enterprise' + ? <>You are currently on the ${user.org.plan ?? 'free'} plan. See our pricing page for information about upgrading. + : <>To request this feature for your enterprise org, contact your admin. +} +``` + + + The information in `user` is only available for logged in users. For logged out users, the value of `user` will be `{}`. To prevent the page from crashing for logged out users, always use optional chaining on your `user` fields. For example, `{user.org?.plan}`. + + +### Page visibility + +Restrict which pages are visible to your users by adding `groups` fields to your pages' frontmatter. By default, every page is visible to every user. + +Users will only see pages for `groups` that they are in. + +```mdx +--- +title: "Managing your users" +description: "Adding and removing users from your organization" +groups: ["admin"] +--- +``` ## User data format @@ -306,4 +364,3 @@ No CORS configuration is needed since the dashboard and docs share the same doma - From a6d79469bd19638d97f47000761706b38dcc7dfc Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 16:28:39 -0700 Subject: [PATCH 08/14] move longer example to later in page --- .../personalization-setup.mdx | 63 ++++++++----------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/authentication-personalization/personalization-setup.mdx b/authentication-personalization/personalization-setup.mdx index 1bddcb1d6..21020612c 100644 --- a/authentication-personalization/personalization-setup.mdx +++ b/authentication-personalization/personalization-setup.mdx @@ -6,9 +6,9 @@ icon: "user-cog" Personalization customizes your documentation for each user when they are logged in. For example, you can prefill their API keys, show content specific to their plan or role, or hide sections they don't need access to. -## Personalized content +## Personalization features -Personalization allows you to customize content with these features. +Customize content with these personalization capabilities. ### API key prefilling @@ -16,39 +16,13 @@ Automatically populate API playground fields with user-specific values by return ### Dynamic MDX content -Display dynamic content based on user information like name, plan, or organization. - -The `user` variable contains information sent to your docs from logged in users. See the [User data format](#user-data-format) section below for more information. - -**Example**: Hello, {user.name ?? 'reader'}! - -```jsx -Hello, {user.name ?? 'reader'}! -``` - -This feature is more powerful when you pair it with custom data about your users. For example, you can give different instructions based on a user's plan. - -**Example**: Authentication is an enterprise feature. { -user.org === undefined -? <>To access this feature, first create an account at the Mintlify dashboard. -: user.org.plan !== 'enterprise' -? <>You are currently on the ${user.org.plan ?? 'free'} plan. See our pricing page for information about upgrading. -: <>To request this feature for your enterprise org, contact your admin. -} +Display dynamic content based on user information like name, plan, or organization using the `user` variable. ```jsx -Authentication is an enterprise feature. { - user.org === undefined - ? <>To access this feature, first create an account at the Mintlify dashboard. - : user.org.plan !== 'enterprise' - ? <>You are currently on the ${user.org.plan ?? 'free'} plan. See our pricing page for information about upgrading. - : <>To request this feature for your enterprise org, contact your admin. -} +Welcome back, {user.firstName}! Your {user.org?.plan} plan includes... ``` - - The information in `user` is only available for logged in users. For logged out users, the value of `user` will be `{}`. To prevent the page from crashing for logged out users, always use optional chaining on your `user` fields. For example, `{user.org?.plan}`. - +See the [User data format](#user-data-format) section below for detailed examples and implementation guidance. ### Page visibility @@ -103,7 +77,7 @@ type User = { > Custom data accessible in your `MDX` content via the `user` variable. Use this for dynamic personalization throughout your documentation. - **Example**: + **Basic example**: ```json { "firstName": "Ronan", "company": "Acme Corp", "plan": "Enterprise" } ``` @@ -113,6 +87,21 @@ type User = { Welcome back, {user.firstName}! Your {user.plan} plan includes... ``` With the example `user` data, this would render as: Welcome back, Ronan! Your Enterprise plan includes... + + **Advanced conditional rendering**: + ```jsx + Authentication is an enterprise feature. { + user.org === undefined + ? <>To access this feature, first create an account at the Mintlify dashboard. + : user.org.plan !== 'enterprise' + ? <>You are currently on the ${user.org.plan ?? 'free'} plan. See our pricing page for information about upgrading. + : <>To request this feature for your enterprise org, contact your admin. + } + ``` + + + The information in `user` is only available for logged-in users. For logged-out users, the value of `user` will be `{}`. To prevent the page from crashing for logged out users, always use optional chaining on your `user` fields. For example, `{user.org?.plan}`. + ### Prerequisites -* A login system that can generate and sign JWTs. -* A backend service that can create redirect URLs. +* A login system that can generate and sign JWTs +* A backend service that can create redirect URLs ### Implementation @@ -184,7 +173,7 @@ Select the handshake method that you want to configure. Modify your existing login flow to include these steps after user login: - * Create a JWT containing the logged in user's info in the `User` format. See the [User data format](#user-data-format) section above for more information. + * Create a JWT containing the logged-in user's info in the `User` format. See the [User data format](#user-data-format) section above for more information. * Sign the JWT with the secret key, using the ES256 algorithm. * Create a redirect URL back to your docs, including the JWT as the hash. @@ -238,8 +227,8 @@ To redirect users to specific sections after login, use this URL format: `https: ### Prerequisites -* An OAuth server that supports the Auth Code with PKCE Flow. -* Ability to create an API endpoint accessible by OAuth access tokens. +* An OAuth server that supports the Auth Code with PKCE Flow +* Ability to create an API endpoint accessible by OAuth access tokens ### Implementation From 706a2b4d4193bb687d876351c5cf7b87448160ef Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 16:32:28 -0700 Subject: [PATCH 09/14] update all ParamFields --- .../personalization-setup.mdx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/authentication-personalization/personalization-setup.mdx b/authentication-personalization/personalization-setup.mdx index 21020612c..c0f20a141 100644 --- a/authentication-personalization/personalization-setup.mdx +++ b/authentication-personalization/personalization-setup.mdx @@ -59,6 +59,7 @@ type User = { Session expiration time in **seconds since epoch**. If the user loads a page after this time, their stored data is automatically deleted and they must reauthenticate. For JWT handshakes: 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). @@ -66,14 +67,16 @@ type User = { - A list of groups that the user belongs to. Pages with a matching `groups` field in their metadata will be visible to this user. + List of groups the user belongs to. Pages with matching `groups` in their frontmatter are visible to this user. **Example**: User with `groups: ["admin", "engineering"]` can access pages tagged with either the `admin` or `engineering` groups. Custom data accessible in your `MDX` content via the `user` variable. Use this for dynamic personalization throughout your documentation. @@ -100,21 +103,22 @@ type User = { ``` - The information in `user` is only available for logged-in users. For logged-out users, the value of `user` will be `{}`. To prevent the page from crashing for logged out users, always use optional chaining on your `user` fields. For example, `{user.org?.plan}`. + The information in `user` is only available for logged-in users. For logged-out users, the value of `user` will be `{}`. To prevent the page from crashing for logged-out users, always use optional chaining on your `user` fields. For example, `{user.org?.plan}`. - User-specific values that will be prefilled in the API playground if supplied. Save users time when testing your APIs with their own data. + User-specific values that prefill API playground fields. Saves users time by auto-populating their data when testing APIs. **Example**: ```json { - "header": { "X-API-Key": "user_api_key_123" }, - "server": { "subdomain": "foo" }, - "query": { "org_id": "12345" } + "header": { "X-API-Key": "user_api_key_123" }, + "server": { "subdomain": "foo" }, + "query": { "org_id": "12345" } } ``` If a user makes requests at a specific subdomain, you can send `{ server: { subdomain: 'foo' } }` as an `apiPlaygroundInputs` field. This value will be prefilled on any API page with the `subdomain` value. From 255e9348def801d6434cfcb3d00e76907e4ded0f Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 16:36:08 -0700 Subject: [PATCH 10/14] copyedit --- authentication-personalization/personalization-setup.mdx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/authentication-personalization/personalization-setup.mdx b/authentication-personalization/personalization-setup.mdx index c0f20a141..647d2816f 100644 --- a/authentication-personalization/personalization-setup.mdx +++ b/authentication-personalization/personalization-setup.mdx @@ -59,7 +59,6 @@ type User = { Session expiration time in **seconds since epoch**. If the user loads a page after this time, their stored data is automatically deleted and they must reauthenticate. For JWT handshakes: 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). @@ -67,7 +66,6 @@ type User = { List of groups the user belongs to. Pages with matching `groups` in their frontmatter are visible to this user. @@ -76,7 +74,6 @@ type User = { Custom data accessible in your `MDX` content via the `user` variable. Use this for dynamic personalization throughout your documentation. @@ -109,7 +106,6 @@ type User = { User-specific values that prefill API playground fields. Saves users time by auto-populating their data when testing APIs. From 136ef78d21cc6205dfb2ee3de9ce0712cc0df39c Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 16:45:26 -0700 Subject: [PATCH 11/14] copyedit overview --- authentication-personalization/overview.mdx | 142 +++++--------------- 1 file changed, 32 insertions(+), 110 deletions(-) diff --git a/authentication-personalization/overview.mdx b/authentication-personalization/overview.mdx index ffb4aa431..7608e4edf 100644 --- a/authentication-personalization/overview.mdx +++ b/authentication-personalization/overview.mdx @@ -11,132 +11,54 @@ keywords: ["auth"] [Enterprise plans](https://mintlify.com/pricing?ref=authentication) include all authentication methods. -There are three approaches to manage access and customize your documentation based on user information. -- **Authentication**: Complete privacy protection for all content with full content customization. +Choose from three approaches to manage access and customize your documentation based on user information and your security needs: + +- **Full authentication**: Complete privacy protection for all content with full content customization. - **Partial authentication**: Page-by-page access control with full content customization. - **Personalization**: Content customization with **no security guarantees**. All content remains publicly accessible. -**Choose authentication** if you need complete security and privacy for all your documentation, including pages, images, search results, and AI assistant features. - -**Choose partial authentication** if you want some pages to be public and others private. - -**Choose personalization** if you want to customize content based on user information and your documentation can be publicly accessible. - -## Handshake methods - -Authentication and personalization offer multiple handshake methods for controlling access to your content. - -### Available for all methods +### Use case examples -**JSON Web Token (JWT)**: Custom system where you manage user tokens with full control over the login flow. +**Choose full authentication when:** +- Building internal company documentation that contains sensitive information +- Documenting proprietary APIs that require user verification +- Creating customer-specific implementation guides -- Pros of JWT: - - Reduced risk of API endpoint abuse. - - No CORS configuration. - - No restrictions on API URLs. -- Cons of JWT: - - Must be compatible with your existing login flow. - - Dashboard sessions and docs authentication are decoupled, so your team will log into your dashboard and your docs separately. - - When you refresh user data, users must log into your docs again. If your users' data changes frequently, they must log in frequently or risk having stale data in your docs. +**Choose partial authentication when:** +- Offering public getting-started guides with private advanced features +- Running a freemium product where premium users get additional documentation +- Publishing open-source docs with private enterprise sections -**OAuth 2.0**: Third-party login integration like Google, GitHub, or other OAuth providers. +**Choose personalization when:** +- Creating public API documentation that shows user-specific examples +- Building marketing sites that customize content based on user profiles +- Offering public tutorials that adapt to user preferences or skill levels -- Pros of OAuth 2.0: - - Heightened security standard. - - No restrictions on API URLs. -- Cons of OAuth 2.0: - - Requires significant work if setting up an OAuth server for the first time. - - Dashboard sessions and docs authentication are decoupled, so your team will log into your dashboard and your docs separately. +## Handshake methods -### Available for authentication and partial authentication +Choose the method that best fits your existing infrastructure and security requirements. -**Mintlify dashboard**: Allow all of your dashboard users to access your docs. +| Method | Available for | Setup complexity | Best for | +|:-------|:--------------|:-----------------|:----------| +| **JWT** | All approaches | Medium | Custom login flows, maximum security control | +| **OAuth 2.0** | All approaches | High | Third-party auth providers, enterprise security | +| **Mintlify Dashboard** | Authentication only | Low | Teams already using Mintlify dashboard | +| **Password** | Authentication only | Low | Simple shared access without personalization | +| **Shared Session** | Personalization only | Low | Apps with existing session-based auth | -- Pros of Mintlify dashboard: - - No configuration required. - - Enables private preview deployments, restricting access to authenticated users only. -- Cons of Mintlify dashboard: - - Requires all users of your docs to have an account in your Mintlify dashboard. +### When to use each method -**Password**: Shared access with a single global password. Used for access control only. Does not allow for personalization. +**JWT**: Use when you have an existing authentication system and want full control over the login flow. Ideal for custom user management or when you need to decouple documentation access from your main application. -- Pros of password: - - Simple setup with no configuration required to add new users, just share the password. -- Cons of password: - - Lose personalization features since there is no way to differentiate users with the same password. - - Must change the password to revoke access. +**OAuth 2.0**: Use when you want to leverage third-party authentication providers (Google, GitHub, etc.) or need enterprise-grade security standards. Best for organizations already using OAuth infrastructure. -### Available for personalization +**Mintlify Dashboard**: Use when your documentation editors are also your documentation readers. Perfect for internal teams who already manage content through the Mintlify dashboard. -**Shared session**: Use the same session token as your dashboard to personalize content. +**Password**: Use for simple access control when you don't need to track individual users or personalize content. Good for contractors, beta users, or temporary access scenarios. -- Pros of shared session: - - Users that are logged into your dashboard are automatically logged into your docs. - - User sessions are persistent so you can refresh data without requiring a new login. - - Minimal setup. -- Cons of shared session: - - Your docs will make a request to your backend. - - You must have a dashboard that uses session authentication. - - CORS configuration is generally required. +**Shared Session**: Use when you want seamless login between your application and documentation. Ideal when users are already authenticated in your main application and you want to personalize their documentation experience. ## Content customization -All three methods allow you to customize content with these features. - -### Dynamic `MDX` content - -Display dynamic content based on user information like name, plan, or organization. - -The `user` variable contains information sent to your docs from logged in users. See [Sending data](/authentication-personalization/sending-data) for more information. - -**Example**: Hello, {user.name ?? 'reader'}! - -```jsx -Hello, {user.name ?? 'reader'}! -``` - -This feature is more powerful when you pair it with custom data about your users. For example, you can give different instructions based on a user's plan. - -**Example**: Authentication is an enterprise feature. { -user.org === undefined -? <>To access this feature, first create an account at the Mintlify dashboard. -: user.org.plan !== 'enterprise' -? <>You are currently on the ${user.org.plan ?? 'free'} plan. See our pricing page for information about upgrading. -: <>To request this feature for your enterprise org, contact your admin. -} - -```jsx -Authentication is an enterprise feature. { - user.org === undefined - ? <>To access this feature, first create an account at the Mintlify dashboard. - : user.org.plan !== 'enterprise' - ? <>You are currently on the ${user.org.plan ?? 'free'} plan. See our pricing page for information about upgrading. - : <>To request this feature for your enterprise org, contact your admin. -} -``` - - - The information in `user` is only available for logged in users. For logged - out users, the value of `user` will be `{}`. To prevent the page from crashing - for logged out users, always use optional chaining on your `user` fields. For - example, `{user.org?.plan}`. - - -### API key prefilling - -Automatically populate API playground fields with user-specific values by returning matching field names in your user data. The field names in your user data must exactly match the names in the API playground for automatic prefilling to work. - -### Page visibility - -Restrict which pages are visible to your users by adding `groups` fields to your pages' frontmatter. By default, every page is visible to every user. - -Users will only see pages for `groups` that they are in. - -```mdx ---- -title: "Managing your users" -description: "Adding and removing users from your organization" -groups: ["admin"] ---- -``` +All three approaches support content personalization features including dynamic MDX content, API key prefilling, and page visibility controls. For detailed implementation guidance, see [Personalization setup](/authentication-personalization/personalization-setup). From e986a47eb5cd17d6418b3d00870f922d47abfdfd Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Wed, 6 Aug 2025 16:50:50 -0700 Subject: [PATCH 12/14] appease the broken link checker --- changelog.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.mdx b/changelog.mdx index 2154a0fef..d2e8d90fb 100644 --- a/changelog.mdx +++ b/changelog.mdx @@ -144,7 +144,7 @@ noindex: true ![screenshot of MCP server generator](/images/changelog/mcpgenerator.png) Generate MCP servers so that AI applications can interact with your docs or APIs. Written content is automatically generated as an MCP server, and you can generate an MCP server from your OpenAPI spec with one click. - Check out [docs on getting started with MCP.](/mcp) + Check out [docs on getting started with MCP.](/ai/model-context-protocol) ## Improvements From 2ca2592b6054324be3328f41737cc048b2f45453 Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Thu, 7 Aug 2025 08:43:12 -0700 Subject: [PATCH 13/14] add OIDC --- authentication-personalization/authentication-setup.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/authentication-personalization/authentication-setup.mdx b/authentication-personalization/authentication-setup.mdx index 944a08b16..b282f02ef 100644 --- a/authentication-personalization/authentication-setup.mdx +++ b/authentication-personalization/authentication-setup.mdx @@ -90,7 +90,7 @@ Your documentation is hosted at `docs.foo.com` and your team uses the dashboard ### Prerequisites -* An OAuth server that supports the Authorization Code Flow. +* 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 personalization features). ### Implementation From bba99973c1e4f6d3b0e2f65eff9f6ee308066503 Mon Sep 17 00:00:00 2001 From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com> Date: Thu, 7 Aug 2025 08:49:55 -0700 Subject: [PATCH 14/14] add logout URL --- authentication-personalization/authentication-setup.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/authentication-personalization/authentication-setup.mdx b/authentication-personalization/authentication-setup.mdx index b282f02ef..ac9e4ca9b 100644 --- a/authentication-personalization/authentication-setup.mdx +++ b/authentication-personalization/authentication-setup.mdx @@ -106,6 +106,7 @@ Your documentation is hosted at `docs.foo.com` and your team uses the dashboard * **Scopes**: Permissions to request. Use multiple scopes if you need different access levels. * **Token URL**: Your OAuth token exchange endpoint. * **Info API URL** (optional): Endpoint to retrieve user info for personalization. If omitted, the OAuth flow will only be used to verify identity and the user info will be empty. + * **Logout URL**: The native logout URL for your OAuth provider. If your provider has a `returnTo` or similar parameter, point it back to your docs URL. 4. Select **Save changes**. @@ -131,6 +132,7 @@ Your documentation is hosted at `foo.com/docs` and you have an existing OAuth se - **Scopes**: `['docs-user-info']` - **Token URL**: `https://auth.foo.com/exchange` - **Info API URL**: `https://api.foo.com/docs/user-info` +- **Logout URL**: `https://auth.foo.com/logout?returnTo=https%3A%2F%2Ffoo.com%2Fdocs` **Create a user info endpoint** at `api.foo.com/docs/user-info`, which requires an OAuth access token with the `docs-user-info` scope, and returns: