Your own pages
Adding a page
Any page of your app under the admin route is part of the dashboard. It uses the dashboard's layout and is for staff only, like the module's pages. Its page meta adds it to the sidebar and search:
<script setup lang="ts">
definePageMeta({
betterAuthAdmin: {
label: 'Reports',
icon: 'i-lucide-chart-bar',
// Optional: staff whose role doesn't grant these get a 403, and no sidebar entry.
permissions: { user: ['set-role'] }
}
})
const { data } = await useFetch('/api/admin/reports')
</script>
<template>
<UDashboardPanel id="reports">
<template #header>
<UDashboardNavbar title="Reports">
<template #leading>
<UDashboardSidebarCollapse />
</template>
</UDashboardNavbar>
</template>
<template #body>
<!-- … -->
</template>
</UDashboardPanel>
</template>
| Page meta | |
|---|---|
label | The sidebar and search entry: words, or a key from messages to translate it. Without one, the page has no entry (for a page you link to, such as a report's details). |
icon | Any icon name, eg i-lucide-chart-bar. |
permissions | The Better Auth Admin permissions the page needs, eg { user: ['set-role'] }. |
order | Where it goes among your own entries, lowest first, then by path. Default 0. |
Your entries go after the module's, before Configuration. Pages with parameters in their path ([id].vue)
don't get one.
The page meta only hides the page. Your API routes must check permissions too.
API routes
requireBetterAuthAdmin checks the Better Auth Admin permissions the same way the module's routes do. It returns
the signed-in user and Better Auth's context. recordBetterAuthAdminAction adds an entry to the
audit log, when it's on:
export default defineEventHandler(async (event) => {
// 401 when signed out, 403 without the permissions.
const { user, context } = await requireBetterAuthAdmin(event, { user: ['list'] })
const report = await buildReport()
await recordBetterAuthAdminAction(event, context, {
action: 'report.export',
actor: user,
target: null,
details: { rows: report.length }
})
return report
})
The audit log shows your own actions under the name you gave them, eg report.export.
In your pages
useBetterAuthAdminCan()checks the signed-in user's permissions, with the same roles as the server:can({ user: ['ban'] }).useBetterAuthAdminPath()turns a path into a URL under the admin route:adminPath('/users').
Replacing a page
Your page at the same path as one of the module's (app/pages/admin/sessions.vue, app/pages/admin/users/[id].vue,
…) replaces it, as with the sign-in pages. The module's sidebar entry for it stays and leads to
yours.