Permissions

This document explains the comprehensive permission system implemented in Nuxt Auto Admin.

Permissions

This document explains the comprehensive permission system implemented in Nuxt Auto Admin.

Configuration

Add permission configuration to your nuxt.config.ts:

export default defineNuxtConfig({
  autoAdmin: {
    permissions: {
      // How to handle buttons when user lacks permission
      // 'disable' = show buttons but disable them (default)
      // 'hide' = completely hide buttons
      unauthorizedButtons: 'disable',

      // How to handle sidebar items when user lacks permission
      // 'hide' = completely hide items from sidebar (default)
      // 'disable' = show items but in disabled state (grayed out, not clickable)
      unauthorizedSidebarItems: 'hide'
    }
  }
})

Features

1. Button Behavior

Buttons respect the unauthorizedButtons configuration:

When set to 'disable' (default):

  • Buttons are shown but disabled
  • Forms show with all fields disabled
  • User sees an orange warning banner indicating limited access
  • Better UX - user can see what they could do with proper permissions

When set to 'hide':

  • Buttons are completely hidden from UI
  • Forms show a red permission denied message
  • Stricter access control

Affected buttons:

  • "Create New" button on list pages
  • "Edit" and "Delete" buttons on detail pages
  • "Save" button on edit/create forms
  • Action buttons in table context menus (always shown but disabled)

2. Sidebar Menu Items

Sidebar items respect the unauthorizedSidebarItems configuration:

When set to 'hide' (default):

  • Resources without any permissions are removed from sidebar
  • Cleaner UI showing only accessible resources

When set to 'disable':

  • Resources without permissions are shown but grayed out
  • Not clickable (rendered as <div> instead of <NuxtLink>)
  • User can see what resources exist but can't access them

3. Table Context Menu

The dropdown menu in table rows now shows all actions but disables them based on permissions:

// Items are always shown in menu
items = [
  { label: 'View', icon: 'i-heroicons-eye', onSelect: ... },
  { label: 'Edit', icon: 'i-heroicons-pencil', disabled: !canUpdate, onSelect: ... },
  { label: 'Delete', icon: 'i-heroicons-trash', disabled: !canDelete, onSelect: ... }
]

4. Direct URL Access Protection

A global middleware (permissions.global.ts) intercepts all admin routes and checks permissions:

  • Checks if user has any permission for the resource
  • Returns 403 Forbidden if no permission
  • Shows nice error page with "Go Back" and "Go to Dashboard" buttons
  • Works for both resource routes and custom pages

5. Custom Pages Permissions

Custom pages can define permissions in two ways:

Using permission strings:

customPages: [
  {
    name: 'settings',
    label: 'Settings',
    path: 'settings',
    icon: 'i-heroicons-cog-6-tooth',
    // Single permission
    permissions: 'admin'
    // OR multiple permissions (user needs ALL)
    // permissions: ['admin', 'settings.manage']
  }
]

Using canAccess function:

customPages: [
  {
    name: 'analytics',
    label: 'Analytics',
    path: 'analytics',
    icon: 'i-heroicons-chart-bar',
    canAccess: async (user) => {
      // Custom logic
      return user?.role === 'admin' || user?.permissions?.includes('analytics.view')
    }
  }
]

6. Form Disabled State

When a user lacks update permission but unauthorizedButtons is set to 'disable':

  • All form fields are disabled via cascading disabled prop
  • Save button is disabled
  • Reset button is disabled
  • M2M relation cards are disabled (select + save buttons)
  • Orange warning banner shows "Limited Access" message

7. Permission Denied Pages

Users see appropriate error messages when accessing unauthorized pages:

403 Forbidden Error:

  • Shows permission denied icon
  • Clear error message
  • "Go Back" and "Go to Dashboard" buttons
  • Consistent styling with the rest of the admin panel

Components Updated

Pages

  • admin/[resource]/index.vue - List page with Create button
  • admin/[resource]/[id].vue - Detail page with Edit/Delete buttons and read permission check
  • admin/[resource]/[id]/edit.vue - Edit page with disabled form option
  • admin/[resource]/new.vue - Create page with disabled form option
  • admin/error.vue - Error page for permission denied and other errors

Components

  • ResourceTable.vue - Context menu actions always shown but disabled
  • ResourceForm.vue - Accepts disabled prop
  • AutoForm.vue - Cascades disabled to all fields and buttons
  • AutoField.vue - Passes disabled to widgets
  • M2MRelationCard.vue - Supports disabled state
  • ResourceNavLink.vue - Shows resource links based on permissions
  • CustomPageNavLink.vue - Shows custom page links based on permissions
  • AdminSidebar.vue - Filters/disables items based on config
  • PermissionDeniedPage.vue - Reusable permission denied component

New Files

  • composables/useAdminConfig.ts - Access admin configuration
  • middleware/permissions.global.ts - Global route guard
  • components/PermissionDeniedPage.vue - Permission denied UI
  • pages/admin/error.vue - Error page handler

Permission Checks

The system uses the existing useAdminPermissions composable which provides:

const {
  canCreate,
  canRead,
  canUpdate,
  canDelete,
  hasAnyPermission,
  isLoading,
  getPermissionDeniedMessage
} = useAdminPermissions(resourceName)

Examples

Example 1: Strict Access Control

autoAdmin: {
  permissions: {
    unauthorizedButtons: 'hide',
    unauthorizedSidebarItems: 'hide'
  }
}

Result:

  • Users only see what they can access
  • No disabled buttons or grayed out items
  • Cleaner, simpler UI
  • Users might not know what they're missing

Example 2: Transparent Access Control

autoAdmin: {
  permissions: {
    unauthorizedButtons: 'disable',
    unauthorizedSidebarItems: 'disable'
  }
}

Result:

  • Users see all features but can't use unauthorized ones
  • Clear indication of what exists but is restricted
  • Better for discovering what permissions they might need
  • More helpful warning messages

Example 3: Balanced Approach (Default)

autoAdmin: {
  permissions: {
    unauthorizedButtons: 'disable',
    unauthorizedSidebarItems: 'hide'
  }
}

Result:

  • Sidebar is clean (only shows accessible resources)
  • Within accessible resources, users see disabled buttons
  • Good balance between discoverability and simplicity

Best Practices

  1. Choose based on your use case:
    • Hide buttons/items for external users or strict security
    • Disable buttons/items for internal users who might request access
  2. Custom pages should always use canAccess for complex permission logic
  3. The middleware protects all routes - even if UI shows something, the middleware will block unauthorized access
  4. Test both configurations to see which provides better UX for your users
  5. Permission denied messages are customizable via the getPermissionDeniedMessage function

Migration

If you're upgrading from a previous version:

  1. Add the permissions config to your nuxt.config.ts (optional, has defaults)
  2. Existing functionality works as before
  3. The default behavior (unauthorizedButtons: 'disable') is more permissive than the old hide-only behavior
  4. If you want the old behavior, set unauthorizedButtons: 'hide'

Need a Landing Page?

Modern landing pages with optional modules (blog, docs, forms, i18n). Let's discuss your project.

Build Your MVP

Full-stack SaaS development. Expert in database design, multi-tenancy, and scalable architecture.

Deployment Help

Dockerize your backend, set up CI/CD pipelines, deploy to Cloudflare or Hetzner. Early-stage setup.

Suggest a SaaS Tool

Missing a calculator or tool? Suggest what you'd like to see on our site.