When building a secured application, you often need to expose certain parts of your API to the public while keeping others locked down. In Nuxt Auto CRUD, we handle this through a robust Role-Based Access Control (RBAC) system.
However, your frontend application needs to know what it is allowed to do, even for a guest user who hasn't logged in yet. This is where the /api/public-permissions endpoint comes in.
By default, your front-end components (like buttons, forms, or navigation items) might be hidden or disabled based on user roles (like admin or manager).
But what about a public visitor?
If your abilities logic only checks user.permissions, a guest user (where user is null) will fail every check, leading to a broken or completely empty UI.
We solved this by explicitly fetching the permissions granted to the public role and storing them in a way that our frontend authorization logic can access.
We created a simple server endpoint that fetches all permissions associated with the public role from the database.
// server/api/public-permissions.get.ts
export default eventHandler(async () => {
return await getPublicPermissions()
})
This returns a JSON object mapped by resource:
{
"testimonials": ["create", "read", "list"],
"products": ["read", "list"]
}
abilities.tsOur abilities.ts file acts as the bridge. It combines three checks:
Here is the simplified logic:
// shared/utils/abilities.ts
let publicPermissionsCache = null
export const abilityLogic = async (user, model, action) => {
// 1. Admin Override
if (user?.role === 'admin') return true
// 2. Logged-in User Permissions
if (user?.permissions?.[model]?.includes(action)) return true
// 3. Fallback to Public Permissions
// Fetch only once and cache it on the client side
if (!publicPermissionsCache) {
publicPermissionsCache = await $fetch('/api/public-permissions')
.catch(() => ({}))
}
return publicPermissionsCache[model]?.includes(action) || false
}
You might ask, "Why not just hardcode the public permissions in the frontend?"
Dynamic & Database-Driven: By fetching them from the API, your public permissions remain defined in your database (specifically, the permissions table linked to the public role).
This means you can change what guests can do (e.g., turn off public registration or comments) via your Admin Dashboard without deploying new code.
This pattern ensures your frontend is smart enough to handle guest users gracefully. By adhering to the single source of truth (your database permissions), you keep your app secure and flexible.
Nuxt Runtime Config & Environment Variables
Learn how to manage configuration in Nuxt 3 using runtimeConfig and automatic environment variable mapping.
Powering AI Agents with MCP & Nuxt Auto CRUD
Harness the Model Context Protocol (MCP) to transform your Nuxt 4 application into an agent-first ecosystem.