Try Live
Add Docs
Rankings
Pricing
Docs
Install
Theme
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Nuxt Users
https://github.com/rrd108/nuxt-users
Admin
A user authentication module for Nuxt 3 and 4 with database support, role-based access control, and
...
Tokens:
143,413
Snippets:
1,057
Trust Score:
8.3
Update:
3 months ago
Context
Skills
Chat
Benchmark
92.7
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Nuxt Users Module Nuxt Users is a comprehensive authentication and user management module for Nuxt 3 and Nuxt 4 applications. It provides a complete, production-ready solution with zero-configuration setup, supporting multiple databases (SQLite, MySQL, PostgreSQL), secure password handling with bcrypt, role-based access control, password reset functionality, and pre-built Vue components. The module is designed with security-first principles, featuring a whitelist-based authorization system and automatic session management. The module integrates seamlessly into Nuxt applications through a single module registration, automatically setting up API endpoints, database tables, authentication middleware, and client-side composables. It includes a powerful CLI for database operations, user creation, and migrations. With TypeScript support throughout and extensive customization options, it scales from simple authentication needs to complex multi-tenant applications while maintaining developer-friendly defaults. ## Installation and Basic Setup ### Zero-Config Installation Install the module and required dependencies, then add to your Nuxt configuration for immediate use with SQLite database. ```bash # Install module and dependencies npm install nuxt-users db0 better-sqlite3 bcrypt nodemailer # Initialize database npx nuxt-users migrate # Create admin user npx nuxt-users create-user -e admin@example.com -n "Admin User" -p password123 -r admin ``` ```typescript // nuxt.config.ts export default defineNuxtConfig({ modules: ['nuxt-users'], nuxtUsers: { auth: { permissions: { admin: ['*'], // Admin can access everything user: ['/profile', '/dashboard', '/api/nuxt-users/me'] } } } }) ``` ### Production Configuration with MySQL Configure for production with MySQL database, custom email provider, and environment variables. ```typescript // nuxt.config.ts export default defineNuxtConfig({ modules: ['nuxt-users'], runtimeConfig: { nuxtUsers: { connector: { name: 'mysql', options: { host: process.env.NUXT_NUXT_USERS_CONNECTOR_OPTIONS_HOST || 'localhost', port: 3306, user: undefined, // Use NUXT_NUXT_USERS_CONNECTOR_OPTIONS_USER env var password: undefined, // Use NUXT_NUXT_USERS_CONNECTOR_OPTIONS_PASSWORD database: undefined // Use NUXT_NUXT_USERS_CONNECTOR_OPTIONS_DATABASE } }, mailer: { host: process.env.NUXT_NUXT_USERS_MAILER_HOST || 'smtp.gmail.com', port: 587, secure: false, auth: { user: undefined, // Use NUXT_NUXT_USERS_MAILER_AUTH_USER pass: undefined // Use NUXT_NUXT_USERS_MAILER_AUTH_PASS }, defaults: { from: '"My App" <noreply@myapp.com>' } }, auth: { tokenExpiration: 1440, // 24 hours rememberMeExpiration: 30, // 30 days whitelist: ['/register', '/about', '/public'], permissions: { admin: ['*'], manager: [ { path: '/api/nuxt-users/*', methods: ['GET', 'PATCH'] }, '/admin/dashboard', '/reports' ], user: ['/profile', '/settings', '/api/nuxt-users/me'] } }, passwordValidation: { minLength: 10, requireUppercase: true, requireLowercase: true, requireNumbers: true, requireSpecialChars: true, preventCommonPasswords: true } } } }) ``` ```bash # .env NUXT_NUXT_USERS_CONNECTOR_OPTIONS_HOST=prod-db.example.com NUXT_NUXT_USERS_CONNECTOR_OPTIONS_USER=app_user NUXT_NUXT_USERS_CONNECTOR_OPTIONS_PASSWORD=secure_password_here NUXT_NUXT_USERS_CONNECTOR_OPTIONS_DATABASE=production_db NUXT_NUXT_USERS_MAILER_HOST=smtp.sendgrid.net NUXT_NUXT_USERS_MAILER_AUTH_USER=apikey NUXT_NUXT_USERS_MAILER_AUTH_PASS=SG.xxxxxxxxxxxxxxxxxxxxx ``` ## User Authentication with useAuthentication ### Login with Remember Me Handle user login with optional persistent sessions across browser restarts. ```vue <script setup> import { useAuthentication } from '#imports' const { login, user, isAuthenticated } = useAuthentication() const email = ref('') const password = ref('') const rememberMe = ref(false) const error = ref('') const loading = ref(false) const handleLogin = async () => { loading.value = true error.value = '' try { const response = await $fetch('/api/nuxt-users/session', { method: 'POST', body: { email: email.value, password: password.value } }) // Update local state with rememberMe preference login(response.user, rememberMe.value) // Redirect to dashboard await navigateTo('/dashboard') } catch (err) { error.value = err.data?.statusMessage || 'Login failed' } finally { loading.value = false } } </script> <template> <div v-if="!isAuthenticated"> <form @submit.prevent="handleLogin"> <input v-model="email" type="email" placeholder="Email" required /> <input v-model="password" type="password" placeholder="Password" required /> <label> <input v-model="rememberMe" type="checkbox" /> Remember me for 30 days </label> <button type="submit" :disabled="loading"> {{ loading ? 'Logging in...' : 'Login' }} </button> <p v-if="error" class="error">{{ error }}</p> </form> </div> <div v-else> <h2>Welcome, {{ user.name }}!</h2> <p>Email: {{ user.email }}</p> <p>Role: {{ user.role }}</p> </div> </template> ``` ### Logout and Session Management Implement logout with confirmation and automatic cleanup of local storage. ```vue <script setup> import { useAuthentication } from '#imports' const { logout, user, isAuthenticated } = useAuthentication() const showConfirm = ref(false) const loggingOut = ref(false) const handleLogout = async () => { loggingOut.value = true try { await logout() await navigateTo('/login') } catch (err) { console.error('Logout error:', err) // Force logout even if API call fails await navigateTo('/login') } finally { loggingOut.value = false showConfirm.value = false } } </script> <template> <div v-if="isAuthenticated" class="user-menu"> <div class="user-info"> <span>{{ user.name }}</span> <span class="role-badge">{{ user.role }}</span> </div> <button @click="showConfirm = true">Logout</button> <div v-if="showConfirm" class="modal"> <p>Are you sure you want to logout?</p> <button @click="handleLogout" :disabled="loggingOut"> {{ loggingOut ? 'Logging out...' : 'Yes, Logout' }} </button> <button @click="showConfirm = false">Cancel</button> </div> </div> </template> ``` ### Automatic Session Restoration Restore user session on app startup with server-side validation. ```vue <script setup> import { useAuthentication } from '#imports' const { user, initializeUser, fetchUser, isAuthenticated } = useAuthentication() // User is automatically initialized on app startup via plugin // Manual initialization is only needed for special cases onMounted(async () => { // Example: Force refresh user data from server if (isAuthenticated.value) { try { await fetchUser() console.log('User data refreshed:', user.value) } catch (err) { console.error('Failed to refresh user:', err) } } }) // Watch for changes to user state watch(user, (newUser) => { if (newUser) { console.log('User logged in:', newUser.name) } else { console.log('User logged out') } }) </script> <template> <div> <div v-if="isAuthenticated"> <h1>Dashboard</h1> <p>Welcome back, {{ user.name }}!</p> <p>Last login: {{ new Date(user.updated_at).toLocaleString() }}</p> </div> <div v-else> <p>Please log in to continue</p> <NuxtLink to="/login">Go to Login</NuxtLink> </div> </div> </template> ``` ## User Registration API ### POST /api/nuxt-users/register Register a new user with email confirmation workflow. ```bash curl -X POST http://localhost:3000/api/nuxt-users/register \ -H "Content-Type: application/json" \ -d '{ "email": "newuser@example.com", "name": "John Doe", "password": "SecurePass123!" }' ``` ```json { "user": { "id": 1, "email": "newuser@example.com", "name": "John Doe", "role": "user", "active": false, "created_at": "2024-01-01T00:00:00.000Z", "updated_at": "2024-01-01T00:00:00.000Z" }, "message": "Registration successful! Please check your email to confirm your account." } ``` ```vue <script setup> const form = ref({ email: '', name: '', password: '', passwordConfirm: '' }) const error = ref('') const success = ref(false) const loading = ref(false) const register = async () => { if (form.value.password !== form.value.passwordConfirm) { error.value = 'Passwords do not match' return } loading.value = true error.value = '' try { const response = await $fetch('/api/nuxt-users/register', { method: 'POST', body: { email: form.value.email, name: form.value.name, password: form.value.password } }) success.value = true console.log('Registration successful:', response) } catch (err) { error.value = err.data?.statusMessage || 'Registration failed' } finally { loading.value = false } } </script> ``` ### GET /api/nuxt-users/confirm-email Confirm user email address and activate account. ```bash curl "http://localhost:3000/api/nuxt-users/confirm-email?token=abc123def456&email=newuser@example.com" ``` ```json { "success": true, "message": "Email confirmed successfully! Your account is now active. You can now log in." } ``` ```vue <script setup> const route = useRoute() const confirming = ref(true) const error = ref('') const success = ref(false) onMounted(async () => { const { token, email } = route.query if (!token || !email) { error.value = 'Invalid confirmation link' confirming.value = false return } try { const response = await $fetch('/api/nuxt-users/confirm-email', { method: 'GET', query: { token, email } }) success.value = true setTimeout(() => navigateTo('/login'), 3000) } catch (err) { error.value = err.data?.statusMessage || 'Confirmation failed' } finally { confirming.value = false } }) </script> <template> <div class="confirmation-page"> <div v-if="confirming"> <h2>Confirming your email...</h2> </div> <div v-else-if="success"> <h2>✓ Email Confirmed!</h2> <p>Your account is now active. Redirecting to login...</p> </div> <div v-else> <h2>✗ Confirmation Failed</h2> <p>{{ error }}</p> </div> </div> </template> ``` ## User Session API ### POST /api/nuxt-users/session Authenticate user and create session. ```bash curl -X POST http://localhost:3000/api/nuxt-users/session \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com", "password": "password123" }' ``` ```json { "user": { "id": 1, "email": "user@example.com", "name": "John Doe", "role": "user", "active": true, "created_at": "2024-01-01T00:00:00.000Z", "updated_at": "2024-01-01T00:00:00.000Z" } } ``` ### DELETE /api/nuxt-users/session Logout current user and invalidate session. ```bash curl -X DELETE http://localhost:3000/api/nuxt-users/session \ -H "Cookie: nuxt-users-auth-token=your_token_here" ``` ```json { "message": "Logged out successfully" } ``` ## User Management API ### GET /api/nuxt-users Get paginated list of all users (admin only). ```bash curl "http://localhost:3000/api/nuxt-users?page=1&limit=10" \ -H "Cookie: nuxt-users-auth-token=admin_token" ``` ```json { "users": [ { "id": 1, "email": "admin@example.com", "name": "Admin User", "role": "admin", "active": true, "created_at": "2024-01-01T00:00:00.000Z", "updated_at": "2024-01-01T00:00:00.000Z" } ], "pagination": { "page": 1, "limit": 10, "total": 1, "totalPages": 1, "hasNext": false, "hasPrev": false } } ``` ```vue <script setup> import { useUsers } from '#imports' const { users, pagination, loading, error, fetchUsers } = useUsers() onMounted(async () => { await fetchUsers(1, 20) }) const loadMore = async () => { if (pagination.value?.hasNext) { await fetchUsers(pagination.value.page + 1) } } </script> <template> <div class="users-list"> <h2>Users ({{ pagination?.total || 0 }})</h2> <div v-if="loading">Loading...</div> <div v-else-if="error" class="error">{{ error }}</div> <div v-else> <table> <thead> <tr> <th>ID</th> <th>Name</th> <th>Email</th> <th>Role</th> <th>Status</th> </tr> </thead> <tbody> <tr v-for="user in users" :key="user.id"> <td>{{ user.id }}</td> <td>{{ user.name }}</td> <td>{{ user.email }}</td> <td>{{ user.role }}</td> <td>{{ user.active ? 'Active' : 'Inactive' }}</td> </tr> </tbody> </table> <button v-if="pagination?.hasNext" @click="loadMore" :disabled="loading" > Load More </button> </div> </div> </template> ``` ### POST /api/nuxt-users Create new user (admin only). ```bash curl -X POST http://localhost:3000/api/nuxt-users \ -H "Content-Type: application/json" \ -H "Cookie: nuxt-users-auth-token=admin_token" \ -d '{ "email": "newuser@example.com", "name": "New User", "password": "SecurePass123!", "role": "user" }' ``` ```json { "user": { "id": 2, "email": "newuser@example.com", "name": "New User", "role": "user", "active": true, "created_at": "2024-01-01T00:00:00.000Z", "updated_at": "2024-01-01T00:00:00.000Z" } } ``` ### GET /api/nuxt-users/:id Get user by ID (own profile or admin). ```bash curl http://localhost:3000/api/nuxt-users/1 \ -H "Cookie: nuxt-users-auth-token=user_token" ``` ```json { "user": { "id": 1, "email": "user@example.com", "name": "John Doe", "role": "user", "active": true, "created_at": "2024-01-01T00:00:00.000Z", "updated_at": "2024-01-01T00:00:00.000Z" } } ``` ### PATCH /api/nuxt-users/:id Update user information (own profile or admin). ```bash curl -X PATCH http://localhost:3000/api/nuxt-users/1 \ -H "Content-Type: application/json" \ -H "Cookie: nuxt-users-auth-token=admin_token" \ -d '{ "name": "Updated Name", "role": "manager", "active": true }' ``` ```json { "user": { "id": 1, "email": "user@example.com", "name": "Updated Name", "role": "manager", "active": true, "created_at": "2024-01-01T00:00:00.000Z", "updated_at": "2024-01-01T12:30:00.000Z" } } ``` ### DELETE /api/nuxt-users/:id Delete user (admin only). ```bash curl -X DELETE http://localhost:3000/api/nuxt-users/2 \ -H "Cookie: nuxt-users-auth-token=admin_token" ``` ```json { "success": true } ``` ```vue <script setup> import { useUsers } from '#imports' const { removeUser, users } = useUsers() const deleting = ref(false) const confirmDelete = async (userId) => { if (!confirm('Are you sure you want to delete this user?')) return deleting.value = true try { await removeUser(userId) alert('User deleted successfully') } catch (err) { alert('Failed to delete user: ' + err.message) } finally { deleting.value = false } } </script> ``` ## Current User Profile API ### GET /api/nuxt-users/me Get current authenticated user profile. ```bash curl http://localhost:3000/api/nuxt-users/me \ -H "Cookie: nuxt-users-auth-token=user_token" ``` ```json { "user": { "id": 1, "email": "user@example.com", "name": "John Doe", "role": "user", "active": true, "created_at": "2024-01-01T00:00:00.000Z", "updated_at": "2024-01-01T00:00:00.000Z" } } ``` ```vue <script setup> const { data: profile, refresh, error } = await useFetch('/api/nuxt-users/me') const updateProfile = async () => { await refresh() } </script> <template> <div v-if="profile"> <h2>My Profile</h2> <p>Name: {{ profile.user.name }}</p> <p>Email: {{ profile.user.email }}</p> <p>Role: {{ profile.user.role }}</p> <p>Member since: {{ new Date(profile.user.created_at).toLocaleDateString() }}</p> </div> </template> ``` ### PATCH /api/nuxt-users/me Update current user profile. ```bash curl -X PATCH http://localhost:3000/api/nuxt-users/me \ -H "Content-Type: application/json" \ -H "Cookie: nuxt-users-auth-token=user_token" \ -d '{ "name": "Johnathan Doe", "email": "john.doe@newemail.com" }' ``` ```json { "user": { "id": 1, "email": "john.doe@newemail.com", "name": "Johnathan Doe", "role": "user", "active": true, "created_at": "2024-01-01T00:00:00.000Z", "updated_at": "2024-01-01T13:45:00.000Z" } } ``` ### PATCH /api/nuxt-users/password Update current user password. ```bash curl -X PATCH http://localhost:3000/api/nuxt-users/password \ -H "Content-Type: application/json" \ -H "Cookie: nuxt-users-auth-token=user_token" \ -d '{ "currentPassword": "oldPassword123", "newPassword": "NewSecurePass456!", "newPasswordConfirmation": "NewSecurePass456!" }' ``` ```json { "message": "Password updated successfully" } ``` ```vue <script setup> const form = ref({ currentPassword: '', newPassword: '', newPasswordConfirmation: '' }) const error = ref('') const success = ref(false) const loading = ref(false) const updatePassword = async () => { if (form.value.newPassword !== form.value.newPasswordConfirmation) { error.value = 'New passwords do not match' return } loading.value = true error.value = '' success.value = false try { await $fetch('/api/nuxt-users/password', { method: 'PATCH', body: form.value }) success.value = true form.value = { currentPassword: '', newPassword: '', newPasswordConfirmation: '' } setTimeout(() => success.value = false, 3000) } catch (err) { error.value = err.data?.statusMessage || 'Failed to update password' } finally { loading.value = false } } </script> <template> <form @submit.prevent="updatePassword"> <h3>Change Password</h3> <input v-model="form.currentPassword" type="password" placeholder="Current Password" required /> <input v-model="form.newPassword" type="password" placeholder="New Password" required /> <input v-model="form.newPasswordConfirmation" type="password" placeholder="Confirm New Password" required /> <button type="submit" :disabled="loading"> {{ loading ? 'Updating...' : 'Update Password' }} </button> <p v-if="success" class="success">Password updated successfully!</p> <p v-if="error" class="error">{{ error }}</p> </form> </template> ``` ## Password Reset API ### POST /api/nuxt-users/password/forgot Request password reset email. ```bash curl -X POST http://localhost:3000/api/nuxt-users/password/forgot \ -H "Content-Type: application/json" \ -d '{ "email": "user@example.com" }' ``` ```json { "message": "If a user with that email exists, a password reset link has been sent." } ``` ```vue <script setup> const email = ref('') const sent = ref(false) const error = ref('') const loading = ref(false) const sendResetEmail = async () => { loading.value = true error.value = '' try { await $fetch('/api/nuxt-users/password/forgot', { method: 'POST', body: { email: email.value } }) sent.value = true } catch (err) { error.value = 'Failed to send reset email' } finally { loading.value = false } } </script> <template> <div class="forgot-password"> <h2>Forgot Password?</h2> <div v-if="!sent"> <p>Enter your email address and we'll send you a reset link.</p> <form @submit.prevent="sendResetEmail"> <input v-model="email" type="email" placeholder="Email Address" required /> <button type="submit" :disabled="loading"> {{ loading ? 'Sending...' : 'Send Reset Link' }} </button> <p v-if="error" class="error">{{ error }}</p> </form> </div> <div v-else class="success-message"> <p>If an account exists with {{ email }}, you'll receive a reset link shortly.</p> <p>Please check your email inbox and spam folder.</p> </div> </div> </template> ``` ### POST /api/nuxt-users/password/reset Reset password with token. ```bash curl -X POST http://localhost:3000/api/nuxt-users/password/reset \ -H "Content-Type: application/json" \ -d '{ "token": "reset-token-from-email", "email": "user@example.com", "password": "NewSecurePass123!", "password_confirmation": "NewSecurePass123!" }' ``` ```json { "message": "Password has been reset successfully. You can now log in with your new password." } ``` ```vue <script setup> const route = useRoute() const form = ref({ token: route.query.token || '', email: route.query.email || '', password: '', password_confirmation: '' }) const success = ref(false) const error = ref('') const loading = ref(false) const resetPassword = async () => { if (form.value.password !== form.value.password_confirmation) { error.value = 'Passwords do not match' return } loading.value = true error.value = '' try { await $fetch('/api/nuxt-users/password/reset', { method: 'POST', body: form.value }) success.value = true setTimeout(() => navigateTo('/login'), 3000) } catch (err) { error.value = err.data?.statusMessage || 'Password reset failed' } finally { loading.value = false } } </script> <template> <div class="reset-password"> <h2>Reset Your Password</h2> <div v-if="!form.token || !form.email" class="error"> Invalid reset link. Please request a new password reset. </div> <div v-else-if="!success"> <form @submit.prevent="resetPassword"> <p>Enter your new password below.</p> <input v-model="form.password" type="password" placeholder="New Password" required /> <input v-model="form.password_confirmation" type="password" placeholder="Confirm Password" required /> <button type="submit" :disabled="loading"> {{ loading ? 'Resetting...' : 'Reset Password' }} </button> <p v-if="error" class="error">{{ error }}</p> </form> </div> <div v-else class="success"> <p>✓ Password reset successful!</p> <p>Redirecting to login...</p> </div> </div> </template> ``` ## Password Validation with usePasswordValidation ### Real-time Password Strength Indicator Validate passwords against configured rules with real-time feedback. ```vue <script setup> import { usePasswordValidation } from '#imports' const password = ref('') const { validate, isValid, errors, strength, score } = usePasswordValidation() watch(password, (newPassword) => { validate(newPassword) }) const strengthColor = computed(() => { const colors = { weak: '#ff4444', medium: '#ffaa00', strong: '#44aa44', very_strong: '#00aa00' } return colors[strength.value] || '#cccccc' }) const strengthLabel = computed(() => { return strength.value.replace('_', ' ').toUpperCase() }) </script> <template> <div class="password-field"> <label>Password</label> <input v-model="password" type="password" placeholder="Enter password" /> <div v-if="password" class="password-feedback"> <div class="strength-bar"> <div class="strength-fill" :style="{ width: `${(score + 1) * 20}%`, backgroundColor: strengthColor }" /> </div> <p class="strength-label" :style="{ color: strengthColor }"> {{ strengthLabel }} (Score: {{ score }}/4) </p> <ul v-if="errors.length > 0" class="errors"> <li v-for="error in errors" :key="error">{{ error }}</li> </ul> <p v-if="isValid" class="valid">✓ Password meets all requirements</p> </div> </div> </template> <style scoped> .strength-bar { height: 8px; background: #eee; border-radius: 4px; overflow: hidden; margin: 8px 0; } .strength-fill { height: 100%; transition: all 0.3s ease; } .errors { color: #ff4444; font-size: 0.9em; margin: 8px 0; } .valid { color: #00aa00; font-weight: bold; } </style> ``` ### Custom Password Validation Rules Override default validation rules for specific use cases. ```vue <script setup> import { usePasswordValidation } from '#imports' const password = ref('') // Custom validation options const customOptions = { minLength: 6, requireUppercase: false, requireNumbers: false, requireSpecialChars: false, preventCommonPasswords: true } const { validate, isValid, errors } = usePasswordValidation(null, customOptions) watch(password, (newPassword) => { validate(newPassword) }) const canSubmit = computed(() => { return password.value && isValid.value }) </script> <template> <form> <input v-model="password" type="password" /> <div v-if="!isValid && password"> <p class="error">Password Requirements:</p> <ul> <li v-for="error in errors" :key="error">{{ error }}</li> </ul> </div> <button type="submit" :disabled="!canSubmit"> {{ canSubmit ? 'Submit' : 'Password Invalid' }} </button> </form> </template> ``` ## Role-Based Authorization with usePublicPaths ### Check Route Access Permissions Verify if current user can access specific routes based on their role. ```vue <script setup> import { useAuthentication, usePublicPaths } from '#imports' const { user } = useAuthentication() const { isAccessiblePath, getAccessiblePaths } = usePublicPaths() const canAccessAdmin = computed(() => { return isAccessiblePath('/admin/dashboard') }) const canManageUsers = computed(() => { return isAccessiblePath('/api/nuxt-users', 'DELETE') }) const canViewReports = computed(() => { return isAccessiblePath('/reports') }) const accessiblePaths = computed(() => { return getAccessiblePaths() }) </script> <template> <nav> <NuxtLink to="/">Home</NuxtLink> <NuxtLink to="/profile">Profile</NuxtLink> <NuxtLink v-if="canAccessAdmin" to="/admin/dashboard"> Admin Dashboard </NuxtLink> <NuxtLink v-if="canViewReports" to="/reports"> Reports </NuxtLink> <div v-if="user?.role === 'admin'"> <h3>Debug: Accessible Paths</h3> <ul> <li v-for="path in accessiblePaths" :key="path">{{ path }}</li> </ul> </div> </nav> </template> ``` ### Conditional Component Rendering Show/hide UI elements based on user permissions. ```vue <script setup> import { useAuthentication, usePublicPaths } from '#imports' const { user } = useAuthentication() const { isAccessiblePath } = usePublicPaths() const permissions = computed(() => ({ canEdit: isAccessiblePath('/api/nuxt-users', 'PATCH'), canDelete: isAccessiblePath('/api/nuxt-users', 'DELETE'), canCreate: isAccessiblePath('/api/nuxt-users', 'POST'), canViewInactive: isAccessiblePath('/api/nuxt-users/inactive', 'GET') })) </script> <template> <div class="user-actions"> <button v-if="permissions.canCreate" @click="createUser"> Create New User </button> <div v-for="userItem in users" :key="userItem.id" class="user-item"> <span>{{ userItem.name }}</span> <button v-if="permissions.canEdit" @click="editUser(userItem.id)"> Edit </button> <button v-if="permissions.canDelete" @click="deleteUser(userItem.id)" class="danger" > Delete </button> </div> <NuxtLink v-if="permissions.canViewInactive" to="/admin/inactive-users"> View Inactive Users </NuxtLink> </div> </template> ``` ## CLI Commands ### Database Migration Initialize or update database schema with all required tables. ```bash # Run all pending migrations npx nuxt-users migrate # Typical output: # ✓ Connected to database # ✓ Migrations table exists # ✓ Running migration: create_users_table # ✓ Running migration: create_personal_access_tokens_table # ✓ Running migration: create_password_reset_tokens_table # ✓ All migrations completed successfully ``` ### User Management Commands Create, modify, and manage users via command line. ```bash # Create admin user npx nuxt-users create-user \ -e admin@example.com \ -n "Admin User" \ -p SecurePassword123! \ -r admin # Create regular user npx nuxt-users create-user \ -e user@example.com \ -n "Regular User" \ -p userpass123 \ -r user # Create user with short flags npx nuxt-users create-user -e dev@example.com -n "Dev User" -p dev123 -r user ``` ### Manual Table Creation Create individual database tables when needed. ```bash # Create users table npx nuxt-users create-users-table # Create personal access tokens table npx nuxt-users create-personal-access-tokens-table # Create password reset tokens table npx nuxt-users create-password-reset-tokens-table # Create migrations tracking table npx nuxt-users create-migrations-table ``` ### Database Schema Modifications Add new columns to existing tables for feature updates. ```bash # Add 'active' column to users table (for account activation) npx nuxt-users add-active-to-users # Add Google OAuth fields to users table npx nuxt-users add-google-oauth-fields # These commands are idempotent - safe to run multiple times ``` ### Project Information Display current configuration and database status. ```bash # Show project info npx nuxt-users project-info # Output example: # Nuxt Users Module - Project Information # # Database Configuration: # Type: mysql # Host: localhost # Database: myapp_production # Tables: users, personal_access_tokens, password_reset_tokens # # Authentication: # Token Expiration: 1440 minutes (24 hours) # Remember Me: 30 days # # Password Policy: # Minimum Length: 8 # Require Uppercase: true # Require Numbers: true ``` ## Pre-built Vue Components ### NUsersLoginForm Component Complete login form with forgot password link and validation. ```vue <template> <div class="login-page"> <h1>Welcome Back</h1> <NUsersLoginForm @success="handleLoginSuccess" @error="handleLoginError" redirect-to="/dashboard" > <template #header> <div class="custom-header"> <img src="/logo.png" alt="Logo" /> <h2>Sign In to Your Account</h2> </div> </template> <template #footer> <div class="login-footer"> <p>Don't have an account? <NuxtLink to="/register">Sign up now</NuxtLink> </p> </div> </template> </NUsersLoginForm> </div> </template> <script setup> const handleLoginSuccess = (user) => { console.log('User logged in:', user.name) // Additional success logic } const handleLoginError = (error) => { console.error('Login failed:', error) // Show notification } </script> ``` ### NUsersRegisterForm Component Registration form with password strength indicator and email confirmation. ```vue <template> <div class="register-page"> <h1>Create Account</h1> <NUsersRegisterForm @success="handleRegistrationSuccess" @error="handleRegistrationError" login-link="/login" > <template #header> <p class="subtitle">Join thousands of users worldwide</p> </template> <template #footer> <div class="terms"> <p>By registering, you agree to our <a href="/terms">Terms of Service</a> and <a href="/privacy">Privacy Policy</a> </p> </div> </template> </NUsersRegisterForm> </div> </template> <script setup> const handleRegistrationSuccess = (data) => { console.log('Registration successful:', data.user) alert(data.message) // Shows email confirmation message navigateTo('/login') } const handleRegistrationError = (error) => { console.error('Registration failed:', error) } </script> ``` ### NUsersResetPasswordForm Component Password reset form that reads token from URL query parameters. ```vue <template> <div class="reset-page"> <h1>Reset Your Password</h1> <p>Enter your new password below.</p> <NUsersResetPasswordForm @success="handleResetSuccess" @error="handleResetError" /> </div> </template> <script setup> const handleResetSuccess = () => { alert('Password reset successful! You can now log in.') navigateTo('/login') } const handleResetError = (error) => { console.error('Password reset failed:', error) alert('Failed to reset password. Please try again or request a new reset link.') } </script> ``` ### NUsersLogoutLink Component Simple logout link with automatic session cleanup. ```vue <template> <header class="app-header"> <nav> <NuxtLink to="/">Home</NuxtLink> <NuxtLink to="/profile">Profile</NuxtLink> <NUsersLogoutLink class="logout-button"> Logout </NUsersLogoutLink> </nav> </header> </template> <style scoped> .logout-button { color: red; cursor: pointer; text-decoration: underline; } </style> ``` ### NUsersList Component Admin component for user management with pagination. ```vue <template> <div class="admin-panel"> <h1>User Management</h1> <NUsersList :page="1" :limit="20" @user-updated="handleUserUpdate" @user-deleted="handleUserDelete" /> </div> </template> <script setup> const handleUserUpdate = (user) => { console.log('User updated:', user) // Show success notification } const handleUserDelete = (userId) => { console.log('User deleted:', userId) // Show success notification } </script> ``` The Nuxt Users module provides a complete authentication and authorization system suitable for projects ranging from simple blogs to complex multi-tenant applications. Its primary use cases include adding user authentication to existing Nuxt applications, building admin dashboards with role-based access control, implementing customer portals with self-service password reset, and creating SaaS applications with team member management. The module's zero-config approach makes it ideal for rapid prototyping while its extensive configuration options support production deployments at scale. Integration patterns typically involve adding the module to an existing Nuxt project, configuring role-based permissions in nuxt.config.ts, using the provided composables (useAuthentication, useUsers) for programmatic access, and leveraging pre-built components for UI implementation. The module integrates seamlessly with Nuxt's server middleware for API route protection, supports SSR and client-side rendering, and can be combined with other Nuxt modules like nuxt-api-shield for enhanced security. Advanced patterns include custom email templates via the mailer configuration, OAuth integration with Google authentication, and multi-database deployments using environment-specific configurations with the runtime config pattern.