Access Control
Limit the access of content.
Overview
Thanks to the flexible design, it is simple to implement access control with Fumadocs.
Loader API
If you are using loader() API, you can create the loaders on-demand, and filter files from content source to restrict accessible content.
For example, this setup with Fumadocs MDX only shows the MDX files with frontmatter permission: public.
import { docs } from 'collections/server';
import { loader, update } from 'fumadocs-core/source';
const filteredSource = update(docs.toFumadocsSource())
.files((files) =>
files.filter((file) => {
// keep meta files (e.g. `meta.json`)
if (file.type === 'meta') return true;
// access file data (type-safe)
return file.data.permission === 'public';
}),
)
.build();
export const source = loader(filteredSource, {
baseUrl: '/docs',
});For more complicated setups, you can turn source into a factory function.
import { docs } from 'collections/server';
import { loader, update } from 'fumadocs-core/source';
// uncached, it's better to cache it in-memory for real use case.
export function createSource(permission: 'public' | 'admin') {
const filteredSource = update(docs.toFumadocsSource())
.files((files) =>
files.filter((file) => {
if (file.type === 'meta') return true;
return file.data.permission === permission;
}),
)
.build();
return loader(filteredSource, {
baseUrl: '/docs',
});
}Advantages
What is special with this approach is that the access is limited at input level, rather than at rendering phase or build-time.
This guarantees the protected content is filtered entirely, and without compromise on flexibility.
Custom Implementation
Without the Loader API, implement access control in TanStack Start, such as in routes or middleware.
For example, to limit access to certain pages:
import { notFound } from '@tanstack/react-router';
import { createServerFn } from '@tanstack/react-start';
import { source } from '@/lib/source';
const serverLoader = createServerFn({ method: 'GET' })
.validator((slugs: string[]) => slugs)
.handler(async ({ data: slugs }) => {
const user = await getUser();
const page = source.getPage(slugs);
if (!page) throw notFound();
if (page.data.permission !== user.permission) throw notFound();
// return page data...
});Note that it is up to you to manage the page tree (sidebar items), search, Markdown routes and other details.
This approach gives the most flexibility, but Fumadocs does not handle the access control. The setup takes more work, so consult the TanStack Start docs when implementing it.
How is this guide?
Last updated on
