|
1 | 1 | --- |
2 | 2 | title: "Personalization Setup" |
3 | | -description: "A list of features unlocked with Personalization" |
4 | | -icon: "user-pen" |
| 3 | +description: "Let users log in for customized documentation experiences" |
| 4 | +icon: "user-cog" |
5 | 5 | --- |
6 | 6 |
|
7 | | -Personalization refers to a suite of features that allow you to customize your |
8 | | -documentation experience based on some information about the user. There are |
9 | | -three major features of Personalization: |
| 7 | +Personalization lets you customize your documentation based on user information. This guide covers setup for each available handshake method. |
10 | 8 |
|
11 | | -- **Customize MDX content** with a user's information, such as their name, plan, or title. |
| 9 | +**Need help choosing?** See the [overview](/authentication-personalization/overview) to compare options. |
12 | 10 |
|
13 | | -- **Prefill API keys** in the API Playground for streamlined use. |
| 11 | +## Configuring personalization |
14 | 12 |
|
15 | | -- **Selectively show pages** in the navigation based on a user's groups. |
| 13 | +Select the handshake method that you want to configure. |
16 | 14 |
|
17 | | -## How to Use |
| 15 | +<Tabs> |
| 16 | + <Tab title="JWT"> |
| 17 | +### Prerequisites |
18 | 18 |
|
19 | | -### Customizing MDX Content |
| 19 | +* An login system that can generate and sign JWTs. |
| 20 | +* A backend service that can create redirect URLs. |
20 | 21 |
|
21 | | -When writing content, you can use the `user` variable to access the information you have sent to your docs. Here's a simple example: |
| 22 | +### Implementation |
22 | 23 |
|
23 | | -Hello, {user.name ?? 'reader'}! |
| 24 | +<Steps> |
| 25 | + <Step title="Generate a private key."> |
| 26 | + 1. In your dashboard, go to [Authentication](https://dashboard.mintlify.com/settings/deployment/authentication). |
| 27 | + 2. Select **Personalization**. |
| 28 | + 3. Select **JWT**. |
| 29 | + 4. Enter the URL of your existing login flow and select **Save changes**. |
| 30 | + 5. Select **Generate new key**. |
| 31 | + 6. Store your key securely where it can be accessed by your backend. |
| 32 | + </Step> |
| 33 | + <Step title="Integrate Mintlify personalization into your login flow."> |
| 34 | + Modify your existing login flow to include these steps after user login: |
| 35 | + |
| 36 | + * Create a JWT containing the logged in user's info in the `User` format. See [Sending Data](/authentication-personalization/sending-data) for more information. |
| 37 | + * Sign the JWT with the secret key, using the ES256 algorithm. |
| 38 | + * Create a redirect URL back to your docs, including the JWT as the hash. |
| 39 | + </Step> |
| 40 | +</Steps> |
24 | 41 |
|
25 | | -```jsx |
26 | | -Hello, {user.name ?? 'reader'}! |
27 | | -``` |
| 42 | +### Example |
28 | 43 |
|
29 | | -This feature becomes even more powerful when paired with custom data about the user. Here's a real world example that allows us to give specific instructions on how to access the Personalization feature based on the customer's existing plan: |
| 44 | +Your documentation is hosted at `docs.foo.com`. You want your docs to be separate from your dashboard (or you don't have a dashboard) and enable personalization. |
30 | 45 |
|
31 | | -Personalization is an enterprise feature. { |
32 | | -user.org === undefined |
33 | | -? <>To access this feature, first create an account at the <a href="https://dashboard.mintlify.com/login">Mintlify dashboard</a>.</> |
34 | | -: user.org.plan !== 'enterprise' |
35 | | -? <>You are currently on the ${user.org.plan ?? 'free'} plan. To speak to our team about upgrading, <a href="mailto:[email protected]">contact our sales team</a>.</> |
36 | | -: <>To request this feature for your enterprise org, <a href="mailto:[email protected]">contact our team</a>.</> |
37 | | -} |
| 46 | +Generate a JWT secret. Then create a login endpoint at `https://foo.com/docs-login` that initiates a login flow to your documentation. |
38 | 47 |
|
39 | | -```jsx |
40 | | -Personalization is an enterprise feature. { |
41 | | - user.org === undefined |
42 | | - ? <>To access this feature, first create an account at the <a href="https://dashboard.mintlify.com/login">Mintlify dashboard</a>.</> |
43 | | - : user.org.plan !== 'enterprise' |
44 | | - ? <>You are currently on the ${user.org.plan ?? 'free'} plan. To speak to our team about upgrading, <a href="mailto:[email protected]">contact our sales team</a>.</> |
45 | | - : <>To request this feature for your enterprise org, <a href="mailto:[email protected]">contact our team</a>.</> |
46 | | -} |
47 | | -``` |
| 48 | +After verifying user credentials: |
| 49 | +* Generate a JWT with user data in Mintlify's format. |
| 50 | +* Sign the JWT and redirect to `https://docs.foo.com#{SIGNED_JWT}`. |
48 | 51 |
|
49 | | -<Note> |
50 | | - The information in `user` is only available after a user has logged in. For |
51 | | - logged out users, the value of `user` will be `{}`. To prevent the page from |
52 | | - crashing for logged-out users, always use optional chaining on your `user` |
53 | | - fields, e.g. `{user.org?.plan}` |
54 | | -</Note> |
| 52 | +```ts |
| 53 | +import * as jose from 'jose'; |
| 54 | +import { Request, Response } from 'express'; |
55 | 55 |
|
56 | | -### Prefilling API Keys |
| 56 | +const TWO_WEEKS_IN_MS = 1000 * 60 * 60 * 24 * 7 * 2; |
57 | 57 |
|
58 | | -If you return API Playground inputs in the user info, they will automatically be prefilled in the API Playground. Make sure the name of the field in the user info is an exact match of the name in the API Playground. |
| 58 | +const signingKey = await jose.importPKCS8(process.env.MINTLIFY_PRIVATE_KEY, 'ES256'); |
59 | 59 |
|
60 | | -### Showing/Hiding Pages |
| 60 | +export async function handleRequest(req: Request, res: Response) { |
| 61 | + const user = { |
| 62 | + expiresAt: Math.floor((Date.now() + TWO_WEEKS_IN_MS) / 1000), |
| 63 | + groups: res.locals.user.groups, |
| 64 | + content: { |
| 65 | + firstName: res.locals.user.firstName, |
| 66 | + lastName: res.locals.user.lastName, |
| 67 | + }, |
| 68 | + }; |
61 | 69 |
|
62 | | -By default, every page is visible to every user. If you want to restrict which pages are visible to your users, you can add a `groups` field in your page metadata. |
63 | | -When determining which pages to show to the user, Mintlify will check which groups the user belongs to. |
64 | | -If the user is not in any of the groups listed in the page metadata, the page will not be shown. |
| 70 | + const jwt = await new jose.SignJWT(user) |
| 71 | + .setProtectedHeader({ alg: 'ES256' }) |
| 72 | + .setExpirationTime('10 s') |
| 73 | + .sign(signingKey); |
65 | 74 |
|
66 | | -```md |
67 | | ---- |
68 | | -title: "Managing Your Users" |
69 | | -description: "Adding and removing users from your organization" |
70 | | -groups: ["admin"] |
71 | | ---- |
| 75 | + return res.redirect(`https://docs.foo.com#${jwt}`); |
| 76 | +} |
72 | 77 | ``` |
73 | 78 |
|
74 | | -Here's a table that displays whether a page is shown for different combinations of `groups` in User and page metadata: |
75 | | -
|
76 | | -| | `groups` not in User | `groups: []` in User | `groups: ['admin']` in User | |
77 | | -| :------------------------------ | :------------------: | :------------------: | :-------------------------: | |
78 | | -| `groups` not in metadata | ✅ | ✅ | ✅ | |
79 | | -| `groups: []` in metadata | ❌ | ❌ | ❌ | |
80 | | -| `groups: ['admin']` in metadata | ❌ | ❌ | ✅ | |
| 79 | +### Preserving page anchors |
| 80 | + |
| 81 | +To redirect users to specific sections after login, use this URL format: `https://docs.foo.com/page#jwt={SIGNED_JWT}&anchor={ANCHOR}`. |
| 82 | + |
| 83 | +**Example**: |
| 84 | +- Original URL: `https://docs.foo.com/quickstart#step-one` |
| 85 | +- Redirect URL: `https://docs.foo.com/quickstart#jwt={SIGNED_JWT}&anchor=step-one` |
| 86 | + |
| 87 | +</Tab> |
| 88 | +<Tab title="OAuth 2.0"> |
| 89 | +### Prerequisites |
| 90 | +- You have an existing OAuth server that supports the PKCE flow. |
| 91 | + - You can create a new API endpoint that can be accessed by the returned OAuth access token. |
| 92 | +### Implementation |
| 93 | + </Tab> |
| 94 | +<Tab title="Shared session"> |
| 95 | +### Prerequisites |
| 96 | + |
| 97 | +- You have a dashboard or other user portal hosted at your domain. |
| 98 | + - Your users' session credentials are stored as cookies. |
| 99 | + - You can create a new API endpoint at the same origin or a subdomain of your dashboard. |
| 100 | + - If your dashboard is at `foo.com`, the **API URL** must start with `foo.com` or `*.foo.com` |
| 101 | + - If your dashboard is at `dash.foo.com`, the **API URL** must start with `dash.foo.com` or `*.dash.foo.com` |
| 102 | + - Your docs are hosted at the same domain as your dashboard. |
| 103 | + - If your dashboard is at `foo.com`, your **docs** must be hosted at `foo.com` or `*.foo.com` |
| 104 | + - If your dashboard is at `*.foo.com`, your **docs** must be hosted at `foo.com` or `*.foo.com` |
| 105 | + |
| 106 | +### Implementation |
| 107 | + </Tab> |
| 108 | +</Tabs> |
81 | 109 |
|
82 | | -<Note> |
83 | | - Note that an empty array in the page metadata is interpreted as "No groups |
84 | | - should see this page." |
85 | | -</Note> |
|
0 commit comments