Authentication
How mock authentication works, demo users and roles, and how to connect a real auth backend.
How Mock Auth Works
Haze Dashboard uses a Pinia store ( app/stores/auth.ts) for mock authentication. There is no real backend or database — authentication is simulated entirely in the browser. The store maintains the current user, computes their role-based permissions, and provides login/logout methods.
On initial load, the store automatically logs in as the Admin user for convenience during development. You can change this behavior by modifying the initial user ref in the store.
Auth Store API
The auth store exposes the following reactive state and methods:
const authStore = useAuthStore()
// Reactive state
authStore.user // Current user object (or null)
authStore.isAuthenticated // Computed boolean
authStore.permissions // Computed string[] based on user's role
// Methods
authStore.hasPermission('edit_orders') // Check a specific permission
authStore.login('admin@haze.dev') // Log in by email (matches demo users)
authStore.logout() // Clear the current userDemo Users
Three demo users are defined in app/utils/permissions.ts:
| Name | Role | Capabilities | |
|---|---|---|---|
| Alex Johnson | admin@haze.dev | Admin | All permissions (view, create, edit, delete for all resources, manage roles) |
| Sarah Chen | editor@haze.dev | Editor | View + create + edit (no delete, no role management) |
| Marcus Webb | viewer@haze.dev | Viewer | View only (no create, edit, or delete) |
Roles & Permissions
Permissions follow the pattern action_resource (e.g., view_orders, create_products, delete_customers). The full permission matrix is defined in app/utils/permissions.ts:
// app/utils/permissions.ts export const rolePermissions: Record= { admin: [ 'view_orders', 'create_orders', 'edit_orders', 'delete_orders', 'view_products', 'create_products', 'edit_products', 'delete_products', 'view_customers', 'create_customers', 'edit_customers', 'delete_customers', 'view_invoices', 'create_invoices', 'edit_invoices', 'delete_invoices', 'view_users', 'create_users', 'edit_users', 'delete_users', 'manage_roles', ], editor: [ 'view_orders', 'create_orders', 'edit_orders', 'view_products', 'create_products', 'edit_products', 'view_customers', 'create_customers', 'edit_customers', 'view_invoices', 'create_invoices', 'edit_invoices', 'view_users', ], viewer: [ 'view_orders', 'view_products', 'view_customers', 'view_invoices', 'view_users', ], }
Role-Based UI
Use the auth store's hasPermission() method to conditionally show or hide UI elements based on the user's role:
This pattern is used throughout the template to hide create/edit/delete buttons for users without the required permissions.
Route Protection (Middleware)
You can protect routes with Nuxt middleware. Create a middleware that checks authentication status and redirects unauthenticated users to the login page:
// app/middleware/auth.ts
export default defineNuxtRouteMiddleware((to) => {
const authStore = useAuthStore()
if (!authStore.isAuthenticated) {
return navigateTo('/auth/login')
}
})Apply the middleware to specific pages:
Connecting Real Authentication
To replace the mock auth with a real backend, you will need to modify:
- 1. Auth store — Replace the in-memory user ref with API calls. The
login()method should POST credentials to your auth endpoint and store the returned token/session. Thelogout()method should clear the token and call the logout endpoint. - 2. Auth middleware — Check for a valid token/session instead of the mock
isAuthenticatedflag. Redirect to login on 401 responses. - 3. Permissions — Fetch the user's permissions from your backend instead of using the static
rolePermissionsmap. - 4. Login/Register pages — Connect the form submissions to your real auth API endpoints.
The rest of the dashboard (components, layouts, pages) does not need to change — it already uses authStore.user and authStore.hasPermission(), which will continue to work with your real data.
Example: Real Login Implementation
Here is how the auth store login method might look when connected to a real API:
// Modified auth store with real API
export const useAuthStore = defineStore('auth', () => {
const user = ref(null)
const token = useCookie('auth-token')
async function login(email: string, password: string) {
const { data } = await useFetch('/api/auth/login', {
method: 'POST',
body: { email, password },
})
if (data.value) {
user.value = data.value.user
token.value = data.value.token
return true
}
return false
}
async function logout() {
await useFetch('/api/auth/logout', { method: 'POST' })
user.value = null
token.value = null
navigateTo('/auth/login')
}
async function fetchUser() {
if (token.value) {
const { data } = await useFetch('/api/auth/me')
user.value = data.value
}
}
return { user, token, login, logout, fetchUser }
})Tip
For SSR-compatible authentication, consider using useCookie() to store the auth token instead of localStorage. Cookies are sent with every request, so Nuxt can verify authentication during server-side rendering.
Next Steps
See the Mock API guide to understand the data layer, or explore Components for the full shared component reference.